From 4fa213c0799e30e49160b7ec9e87f03056ec625b Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 16:06:19 +0530 Subject: [PATCH 01/10] add `entity_leaders` node and field --- .../apps/owasp/api/internal/nodes/common.py | 10 +++++++- .../owasp/api/internal/nodes/entity_member.py | 25 +++++++++++++++++++ backend/apps/owasp/models/common.py | 11 ++++---- 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 backend/apps/owasp/api/internal/nodes/entity_member.py diff --git a/backend/apps/owasp/api/internal/nodes/common.py b/backend/apps/owasp/api/internal/nodes/common.py index 902ed9dc2e..85411adbbe 100644 --- a/backend/apps/owasp/api/internal/nodes/common.py +++ b/backend/apps/owasp/api/internal/nodes/common.py @@ -2,13 +2,21 @@ import strawberry -from apps.github.api.internal.nodes.repository_contributor import RepositoryContributorNode +from apps.github.api.internal.nodes.repository_contributor import ( + RepositoryContributorNode, +) +from apps.owasp.api.internal.nodes.entity_member import EntityMemberNode @strawberry.type class GenericEntityNode(strawberry.relay.Node): """Base node class for OWASP entities with common fields and resolvers.""" + @strawberry.field + def entity_leaders(self) -> list[EntityMemberNode]: + """Resolve entity leaders.""" + return self.entity_leaders + @strawberry.field def leaders(self) -> list[str]: """Resolve leaders.""" diff --git a/backend/apps/owasp/api/internal/nodes/entity_member.py b/backend/apps/owasp/api/internal/nodes/entity_member.py new file mode 100644 index 0000000000..df866131a2 --- /dev/null +++ b/backend/apps/owasp/api/internal/nodes/entity_member.py @@ -0,0 +1,25 @@ +"""OWASP app entity member node.""" + +import strawberry +import strawberry_django + +from apps.github.api.internal.nodes.user import UserNode +from apps.owasp.models.entity_member import EntityMember + + +@strawberry_django.type( + EntityMember, + fields=[ + "role", + "member_name", + "member_email", + "description", + "is_active", + "is_reviewed", + "order", + ], +) +class EntityMemberNode(strawberry.relay.Node): + """Entity member node.""" + + member: UserNode | None diff --git a/backend/apps/owasp/models/common.py b/backend/apps/owasp/models/common.py index 1c6d83cbd3..49b2ed254a 100644 --- a/backend/apps/owasp/models/common.py +++ b/backend/apps/owasp/models/common.py @@ -18,7 +18,6 @@ GITHUB_REPOSITORY_RE, GITHUB_USER_RE, ) -from apps.github.models.user import User from apps.github.utils import get_repository_file_content from apps.owasp.models.entity_member import EntityMember from apps.owasp.models.enums.project import AudienceChoices @@ -116,12 +115,12 @@ def info_md_url(self) -> str | None: ) @property - def entity_leaders(self) -> models.QuerySet[User]: + def entity_leaders(self) -> models.QuerySet[EntityMember]: """Return entity's leaders.""" - return User.objects.filter( - pk__in=self.members.filter(role=EntityMember.Role.LEADER).values_list( - "member_id", flat=True - ) + return EntityMember.objects.filter( + entity_type=ContentType.objects.get_for_model(self.__class__), + entity_id=self.pk, + role=EntityMember.Role.LEADER, ) @property From 89e5fac064eb0a2845700fa9a36cd28d066db2e9 Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 16:40:29 +0530 Subject: [PATCH 02/10] refactor and extract Leaders component --- frontend/__tests__/unit/pages/About.test.tsx | 136 +----------------- frontend/src/app/about/page.tsx | 80 ++++------- .../src/app/chapters/[chapterKey]/page.tsx | 1 + .../src/app/projects/[projectKey]/page.tsx | 1 + frontend/src/components/CardDetailsPage.tsx | 3 + frontend/src/components/Leaders.tsx | 47 ++++++ frontend/src/server/queries/chapterQueries.ts | 11 ++ frontend/src/server/queries/projectQueries.ts | 11 ++ frontend/src/server/queries/userQueries.ts | 2 - .../__generated__/chapterQueries.generated.ts | 4 +- frontend/src/types/__generated__/graphql.ts | 18 +++ .../__generated__/projectQueries.generated.ts | 4 +- .../__generated__/userQueries.generated.ts | 4 +- frontend/src/types/card.ts | 2 + frontend/src/types/chapter.ts | 2 + frontend/src/types/leader.ts | 9 ++ frontend/src/types/project.ts | 2 + 17 files changed, 145 insertions(+), 192 deletions(-) create mode 100644 frontend/src/components/Leaders.tsx create mode 100644 frontend/src/types/leader.ts diff --git a/frontend/__tests__/unit/pages/About.test.tsx b/frontend/__tests__/unit/pages/About.test.tsx index f5fb59060b..199cbd99fb 100644 --- a/frontend/__tests__/unit/pages/About.test.tsx +++ b/frontend/__tests__/unit/pages/About.test.tsx @@ -123,10 +123,6 @@ const mockTopContributorsData = { error: null, } -const mockError = { - error: new Error('GraphQL error'), -} - describe('About Component', () => { let mockRouter: { push: jest.Mock } beforeEach(() => { @@ -216,29 +212,6 @@ describe('About Component', () => { }) }) - test('handles leader data loading error gracefully', async () => { - ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { - return mockProjectData - } else if (options?.variables?.key === 'arkid15r') { - return { data: null, loading: false, error: mockError } - } else if (options?.variables?.key === 'kasya' || options?.variables?.key === 'mamicidal') { - return mockUserData(options?.variables?.key) - } - return { loading: true } - }) - - await act(async () => { - render() - }) - - await waitFor(() => { - expect(screen.getByText("Error loading arkid15r's data")).toBeInTheDocument() - expect(screen.getByText('Kate Golovanova')).toBeInTheDocument() - expect(screen.getByText('Starr Brown')).toBeInTheDocument() - }) - }) - test('renders top contributors section correctly', async () => { await act(async () => { render() @@ -349,68 +322,6 @@ describe('About Component', () => { }) }) - test('LeaderData component shows loading state correctly', async () => { - ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { - return mockProjectData - } else if (options?.variables?.key === 'arkid15r') { - return { data: null, loading: true, error: null } - } else if (options?.variables?.key === 'kasya') { - return mockUserData('kasya') - } else if (options?.variables?.key === 'mamicidal') { - return mockUserData('mamicidal') - } - return { loading: true } - }) - - await act(async () => { - render() - }) - - await waitFor(() => { - expect(screen.getByText('Loading arkid15r...')).toBeInTheDocument() - }) - - await waitFor(() => { - expect(screen.getByText('Kate Golovanova')).toBeInTheDocument() - expect(screen.getByText('Starr Brown')).toBeInTheDocument() - }) - - const loadingMessages = screen.getAllByText(/Loading .+\.\.\./) - expect(loadingMessages).toHaveLength(1) - }) - - test('LeaderData component handles null user data correctly', async () => { - ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { - return mockProjectData - } else if (options?.variables?.key === 'arkid15r') { - return { data: { user: null }, loading: false, error: null } - } else if (options?.variables?.key === 'kasya') { - return mockUserData('kasya') - } else if (options?.variables?.key === 'mamicidal') { - return mockUserData('mamicidal') - } - return { loading: true } - }) - - await act(async () => { - render() - }) - - await waitFor(() => { - expect(screen.getByText('No data available for arkid15r')).toBeInTheDocument() - }) - - await waitFor(() => { - expect(screen.getByText('Kate Golovanova')).toBeInTheDocument() - expect(screen.getByText('Starr Brown')).toBeInTheDocument() - }) - - const noDataMessages = screen.getAllByText(/No data available for .+/) - expect(noDataMessages).toHaveLength(1) - }) - test('handles null project in data response gracefully', async () => { ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { if (options?.variables?.key === 'nest') { @@ -433,29 +344,6 @@ describe('About Component', () => { }) }) - test('handles undefined user data in leader response', async () => { - ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { - return mockProjectData - } else if (options?.variables?.key === 'arkid15r') { - return { data: undefined, loading: false, error: null } - } else if (options?.variables?.key === 'kasya' || options?.variables?.key === 'mamicidal') { - return mockUserData(options?.variables?.key) - } - return { loading: true } - }) - - await act(async () => { - render() - }) - - await waitFor(() => { - expect(screen.getByText('No data available for arkid15r')).toBeInTheDocument() - expect(screen.getByText('Kate Golovanova')).toBeInTheDocument() - expect(screen.getByText('Starr Brown')).toBeInTheDocument() - }) - }) - test('navigates to user details on View Profile button click', async () => { await act(async () => { render() @@ -477,6 +365,7 @@ describe('About Component', () => { avatarUrl: 'https://avatars.githubusercontent.com/u/2201626?v=4', company: 'OWASP', // name is missing + login: 'arkid15r', url: '/members/arkid15r', }, }, @@ -506,29 +395,6 @@ describe('About Component', () => { }) }) - test('shows fallback when user data is missing', async () => { - ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { - if (options?.variables?.key === 'nest') { - return mockProjectData - } else if (options?.variables?.key === 'arkid15r') { - return { data: null, loading: false, error: false } - } else if (options?.variables?.key === 'kasya') { - return mockUserData('kasya') - } else if (options?.variables?.key === 'mamicidal') { - return mockUserData('mamicidal') - } - return { loading: true } - }) - - await act(async () => { - render() - }) - - await waitFor(() => { - expect(screen.getByText(/No data available for arkid15r/i)).toBeInTheDocument() - }) - }) - test('renders LoadingSpinner when project data is loading', async () => { ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { if (options?.variables?.key === 'nest') { diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index 227add56c3..7782694852 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -8,7 +8,6 @@ import { faScroll, faUsers, faTools, - faPersonWalkingArrowRight, faBullseye, faUser, faUsersGear, @@ -18,9 +17,7 @@ import { Tooltip } from '@heroui/tooltip' import upperFirst from 'lodash/upperFirst' import Image from 'next/image' import Link from 'next/link' -import { useRouter } from 'next/navigation' import { useEffect, useState } from 'react' -import FontAwesomeIconWrapper from 'wrappers/FontAwesomeIconWrapper' import { ErrorDisplay, handleAppError } from 'app/global-error' import { GetProjectMetadataDocument, @@ -29,7 +26,6 @@ import { import { GetLeaderDataDocument } from 'types/__generated__/userQueries.generated' import type { Contributor } from 'types/contributor' import type { Project } from 'types/project' -import type { User } from 'types/user' import { technologies, missionContent, @@ -40,17 +36,42 @@ import { } from 'utils/aboutData' import AnchorTitle from 'components/AnchorTitle' import AnimatedCounter from 'components/AnimatedCounter' +import Leaders from 'components/Leaders' import LoadingSpinner from 'components/LoadingSpinner' import Markdown from 'components/MarkdownWrapper' import SecondaryCard from 'components/SecondaryCard' import TopContributorsList from 'components/TopContributorsList' -import UserCard from 'components/UserCard' const leaders = { arkid15r: 'CCSP, CISSP, CSSLP', kasya: 'CC', mamicidal: 'CISSP', } + +const useLeadersData = () => { + const { data: leader1Data, loading: loading1 } = useQuery(GetLeaderDataDocument, { + variables: { key: 'arkid15r' }, + }) + const { data: leader2Data, loading: loading2 } = useQuery(GetLeaderDataDocument, { + variables: { key: 'kasya' }, + }) + const { data: leader3Data, loading: loading3 } = useQuery(GetLeaderDataDocument, { + variables: { key: 'mamicidal' }, + }) + + const isLoading = loading1 || loading2 || loading3 + + const formattedLeaders = [leader1Data?.user, leader2Data?.user, leader3Data?.user] + .filter((user) => user) + .map((user) => ({ + description: leaders[user.login], + memberName: user.name || user.login, + member: user, + })) + + return { formattedLeaders, isLoading } +} + const projectKey = 'nest' const About = () => { @@ -73,6 +94,8 @@ const About = () => { } ) + const { formattedLeaders, isLoading: leadersLoading } = useLeadersData() + const [projectMetadata, setProjectMetadata] = useState(null) const [topContributors, setTopContributors] = useState([]) @@ -100,7 +123,8 @@ const About = () => { !projectMetadataResponse || !topContributorsResponse || (projectMetadataRequestError && !projectMetadata) || - (topContributorsRequestError && !topContributors) + (topContributorsRequestError && !topContributors) || + leadersLoading if (isLoading) { return @@ -141,15 +165,7 @@ const About = () => { - }> -
- {Object.keys(leaders).map((username) => ( -
- -
- ))} -
-
+ {topContributors && ( { ) } -const LeaderData = ({ username }: { username: string }) => { - const { data, loading, error } = useQuery(GetLeaderDataDocument, { - variables: { key: username }, - }) - const router = useRouter() - - if (loading) return

Loading {username}...

- if (error) return

Error loading {username}'s data

- - const user = data?.user - - if (!user) { - return

No data available for {username}

- } - - const handleButtonClick = (user: User) => { - router.push(`/members/${user.login}`) - } - - return ( - , - label: 'View Profile', - onclick: () => handleButtonClick(user), - }} - className="h-64 w-40 bg-inherit" - description={leaders[user.login]} - name={user.name || username} - /> - ) -} - export default About diff --git a/frontend/src/app/chapters/[chapterKey]/page.tsx b/frontend/src/app/chapters/[chapterKey]/page.tsx index 7e5ed3ab3c..b425c42838 100644 --- a/frontend/src/app/chapters/[chapterKey]/page.tsx +++ b/frontend/src/app/chapters/[chapterKey]/page.tsx @@ -63,6 +63,7 @@ export default function ChapterDetailsPage() { { )} + {entityLeaders && entityLeaders.length > 0 && } {topContributors && ( = ({ users }) => { + const router = useRouter() + + const handleButtonClick = (user: Leader) => { + if (user.member) { + router.push(`/members/${user.member.login}`) + } else { + router.push(`/members?q=${encodeURIComponent(user.memberName)}`) + } + } + + return ( + }> +
+ {users.map((user, index) => ( + , + label: 'View Profile', + onclick: () => handleButtonClick(user), + }} + className="h-64 w-42 bg-inherit" + description={user.description} + name={user.member?.name || user.memberName} + /> + ))} +
+
+ ) +} + +export default Leaders diff --git a/frontend/src/server/queries/chapterQueries.ts b/frontend/src/server/queries/chapterQueries.ts index 1714c4bd3c..478be9d260 100644 --- a/frontend/src/server/queries/chapterQueries.ts +++ b/frontend/src/server/queries/chapterQueries.ts @@ -17,6 +17,17 @@ export const GET_CHAPTER_DATA = gql` summary updatedAt url + entityLeaders { + id + description + memberName + member { + id + login + name + avatarUrl + } + } } topContributors(chapter: $key) { id diff --git a/frontend/src/server/queries/projectQueries.ts b/frontend/src/server/queries/projectQueries.ts index f6b3138030..503c6bcbff 100644 --- a/frontend/src/server/queries/projectQueries.ts +++ b/frontend/src/server/queries/projectQueries.ts @@ -11,6 +11,17 @@ export const GET_PROJECT_DATA = gql` key languages leaders + entityLeaders { + id + description + memberName + member { + id + login + name + avatarUrl + } + } level name healthMetricsList(limit: 30) { diff --git a/frontend/src/server/queries/userQueries.ts b/frontend/src/server/queries/userQueries.ts index 5bf0573638..dd9c24cb76 100644 --- a/frontend/src/server/queries/userQueries.ts +++ b/frontend/src/server/queries/userQueries.ts @@ -5,8 +5,6 @@ export const GET_LEADER_DATA = gql` user(login: $key) { id avatarUrl - company - location login name } diff --git a/frontend/src/types/__generated__/chapterQueries.generated.ts b/frontend/src/types/__generated__/chapterQueries.generated.ts index e9266997df..32720a4000 100644 --- a/frontend/src/types/__generated__/chapterQueries.generated.ts +++ b/frontend/src/types/__generated__/chapterQueries.generated.ts @@ -6,7 +6,7 @@ export type GetChapterDataQueryVariables = Types.Exact<{ }>; -export type GetChapterDataQuery = { chapter: { __typename: 'ChapterNode', id: string, isActive: boolean, key: string, name: string, region: string, relatedUrls: Array, suggestedLocation: string | null, summary: string, updatedAt: number, url: string, geoLocation: { __typename: 'GeoLocationType', lat: number, lng: number } | null } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; +export type GetChapterDataQuery = { chapter: { __typename: 'ChapterNode', id: string, isActive: boolean, key: string, name: string, region: string, relatedUrls: Array, suggestedLocation: string | null, summary: string, updatedAt: number, url: string, geoLocation: { __typename: 'GeoLocationType', lat: number, lng: number } | null, entityLeaders: Array<{ __typename: 'EntityMemberNode', id: string, description: string, memberName: string, member: { __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string } | null }> } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; export type GetChapterMetadataQueryVariables = Types.Exact<{ key: Types.Scalars['String']['input']; @@ -16,5 +16,5 @@ export type GetChapterMetadataQueryVariables = Types.Exact<{ export type GetChapterMetadataQuery = { chapter: { __typename: 'ChapterNode', id: string, name: string, summary: string } | null }; -export const GetChapterDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"geoLocation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lng"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"region"}},{"kind":"Field","name":{"kind":"Name","value":"relatedUrls"}},{"kind":"Field","name":{"kind":"Name","value":"suggestedLocation"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"chapter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetChapterDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"geoLocation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lng"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"region"}},{"kind":"Field","name":{"kind":"Name","value":"relatedUrls"}},{"kind":"Field","name":{"kind":"Name","value":"suggestedLocation"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"chapter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const GetChapterMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/types/__generated__/graphql.ts b/frontend/src/types/__generated__/graphql.ts index c2df58b1e9..bf05f4842f 100644 --- a/frontend/src/types/__generated__/graphql.ts +++ b/frontend/src/types/__generated__/graphql.ts @@ -50,6 +50,7 @@ export type ChapterNode = Node & { __typename?: 'ChapterNode'; country: Scalars['String']['output']; createdAt: Scalars['Float']['output']; + entityLeaders: Array; geoLocation?: Maybe; /** The Globally Unique ID of this object */ id: Scalars['ID']['output']; @@ -73,6 +74,7 @@ export type CommitteeNode = Node & { __typename?: 'CommitteeNode'; contributorsCount: Scalars['Int']['output']; createdAt: Scalars['Float']['output']; + entityLeaders: Array; forksCount: Scalars['Int']['output']; /** The Globally Unique ID of this object */ id: Scalars['ID']['output']; @@ -121,6 +123,20 @@ export type CreateProgramInput = { tags?: Array; }; +export type EntityMemberNode = Node & { + __typename?: 'EntityMemberNode'; + description: Scalars['String']['output']; + /** The Globally Unique ID of this object */ + id: Scalars['ID']['output']; + isActive: Scalars['Boolean']['output']; + isReviewed: Scalars['Boolean']['output']; + member?: Maybe; + memberEmail: Scalars['String']['output']; + memberName: Scalars['String']['output']; + order: Scalars['Int']['output']; + role: Scalars['String']['output']; +}; + export type EventNode = Node & { __typename?: 'EventNode'; category: Scalars['String']['output']; @@ -451,6 +467,7 @@ export type ProjectNode = Node & { __typename?: 'ProjectNode'; contributorsCount: Scalars['Int']['output']; createdAt?: Maybe; + entityLeaders: Array; forksCount: Scalars['Int']['output']; healthMetricsLatest?: Maybe; healthMetricsList: Array; @@ -786,6 +803,7 @@ export type SnapshotNode = Node & { __typename?: 'SnapshotNode'; createdAt: Scalars['DateTime']['output']; endAt: Scalars['DateTime']['output']; + entityLeaders: Array; /** The Globally Unique ID of this object */ id: Scalars['ID']['output']; key: Scalars['String']['output']; diff --git a/frontend/src/types/__generated__/projectQueries.generated.ts b/frontend/src/types/__generated__/projectQueries.generated.ts index 9c6790e484..294b4d02b4 100644 --- a/frontend/src/types/__generated__/projectQueries.generated.ts +++ b/frontend/src/types/__generated__/projectQueries.generated.ts @@ -6,7 +6,7 @@ export type GetProjectQueryVariables = Types.Exact<{ }>; -export type GetProjectQuery = { project: { __typename: 'ProjectNode', id: string, contributorsCount: number, forksCount: number, issuesCount: number, isActive: boolean, key: string, languages: Array, leaders: Array, level: string, name: string, repositoriesCount: number, starsCount: number, summary: string, topics: Array, type: string, updatedAt: number, url: string, healthMetricsList: Array<{ __typename: 'ProjectHealthMetricsNode', id: string, createdAt: any, forksCount: number, lastCommitDays: number, lastCommitDaysRequirement: number, lastReleaseDays: number, lastReleaseDaysRequirement: number, openIssuesCount: number, openPullRequestsCount: number, score: number | null, starsCount: number, unassignedIssuesCount: number, unansweredIssuesCount: number }>, recentIssues: Array<{ __typename: 'IssueNode', createdAt: any, organizationName: string | null, repositoryName: string | null, title: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string, url: string } | null }>, recentReleases: Array<{ __typename: 'ReleaseNode', name: string, organizationName: string | null, publishedAt: any | null, repositoryName: string | null, tagName: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }>, repositories: Array<{ __typename: 'RepositoryNode', id: string, contributorsCount: number, forksCount: number, key: string, name: string, openIssuesCount: number, starsCount: number, subscribersCount: number, url: string, organization: { __typename: 'OrganizationNode', login: string } | null }>, recentMilestones: Array<{ __typename: 'MilestoneNode', title: string, openIssuesCount: number, closedIssuesCount: number, repositoryName: string | null, organizationName: string | null, createdAt: any, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }>, recentPullRequests: Array<{ __typename: 'PullRequestNode', createdAt: any, organizationName: string | null, repositoryName: string | null, title: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }> } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; +export type GetProjectQuery = { project: { __typename: 'ProjectNode', id: string, contributorsCount: number, forksCount: number, issuesCount: number, isActive: boolean, key: string, languages: Array, leaders: Array, level: string, name: string, repositoriesCount: number, starsCount: number, summary: string, topics: Array, type: string, updatedAt: number, url: string, entityLeaders: Array<{ __typename: 'EntityMemberNode', id: string, description: string, memberName: string, member: { __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string } | null }>, healthMetricsList: Array<{ __typename: 'ProjectHealthMetricsNode', id: string, createdAt: any, forksCount: number, lastCommitDays: number, lastCommitDaysRequirement: number, lastReleaseDays: number, lastReleaseDaysRequirement: number, openIssuesCount: number, openPullRequestsCount: number, score: number | null, starsCount: number, unassignedIssuesCount: number, unansweredIssuesCount: number }>, recentIssues: Array<{ __typename: 'IssueNode', createdAt: any, organizationName: string | null, repositoryName: string | null, title: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string, url: string } | null }>, recentReleases: Array<{ __typename: 'ReleaseNode', name: string, organizationName: string | null, publishedAt: any | null, repositoryName: string | null, tagName: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }>, repositories: Array<{ __typename: 'RepositoryNode', id: string, contributorsCount: number, forksCount: number, key: string, name: string, openIssuesCount: number, starsCount: number, subscribersCount: number, url: string, organization: { __typename: 'OrganizationNode', login: string } | null }>, recentMilestones: Array<{ __typename: 'MilestoneNode', title: string, openIssuesCount: number, closedIssuesCount: number, repositoryName: string | null, organizationName: string | null, createdAt: any, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }>, recentPullRequests: Array<{ __typename: 'PullRequestNode', createdAt: any, organizationName: string | null, repositoryName: string | null, title: string, url: string, author: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }> } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; export type GetProjectMetadataQueryVariables = Types.Exact<{ key: Types.Scalars['String']['input']; @@ -33,7 +33,7 @@ export type SearchProjectNamesQueryVariables = Types.Exact<{ export type SearchProjectNamesQuery = { searchProjects: Array<{ __typename: 'ProjectNode', id: string, name: string }> }; -export const GetProjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"languages"}},{"kind":"Field","name":{"kind":"Name","value":"leaders"}},{"kind":"Field","name":{"kind":"Name","value":"level"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"healthMetricsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"30"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"openPullRequestsCount"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"unassignedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"unansweredIssuesCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentIssues"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentReleases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"tagName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"}}]}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"subscribersCount"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositoriesCount"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"topics"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentPullRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetProjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"languages"}},{"kind":"Field","name":{"kind":"Name","value":"leaders"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"level"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"healthMetricsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"30"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"openPullRequestsCount"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"unassignedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"unansweredIssuesCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentIssues"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentReleases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"tagName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"}}]}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"subscribersCount"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositoriesCount"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"topics"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentPullRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const GetProjectMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProjectMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"25"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"progress"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetTopContributorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTopContributors"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"excludedUsernames"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hasFullName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"excludedUsernames"},"value":{"kind":"Variable","name":{"kind":"Name","value":"excludedUsernames"}}},{"kind":"Argument","name":{"kind":"Name","value":"hasFullName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasFullName"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const SearchProjectNamesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchProjectNames"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchProjects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/types/__generated__/userQueries.generated.ts b/frontend/src/types/__generated__/userQueries.generated.ts index 0cd3c6ae2e..8516cb0dae 100644 --- a/frontend/src/types/__generated__/userQueries.generated.ts +++ b/frontend/src/types/__generated__/userQueries.generated.ts @@ -6,7 +6,7 @@ export type GetLeaderDataQueryVariables = Types.Exact<{ }>; -export type GetLeaderDataQuery = { user: { __typename: 'UserNode', id: string, avatarUrl: string, company: string, location: string, login: string, name: string } | null }; +export type GetLeaderDataQuery = { user: { __typename: 'UserNode', id: string, avatarUrl: string, login: string, name: string } | null }; export type GetUserDataQueryVariables = Types.Exact<{ key: Types.Scalars['String']['input']; @@ -23,6 +23,6 @@ export type GetUserMetadataQueryVariables = Types.Exact<{ export type GetUserMetadataQuery = { user: { __typename: 'UserNode', id: string, bio: string, login: string, name: string } | null }; -export const GetLeaderDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetLeaderData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetLeaderDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetLeaderData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const GetUserDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"recentIssues"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}},{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}},{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentPullRequests"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}},{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentReleases"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}},{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isPreRelease"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"tagName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributedRepositories"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}}]}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"subscribersCount"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"contributionsCount"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"followersCount"}},{"kind":"Field","name":{"kind":"Name","value":"followingCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"publicRepositoriesCount"}},{"kind":"Field","name":{"kind":"Name","value":"releasesCount"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]} as unknown as DocumentNode; export const GetUserMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"login"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/types/card.ts b/frontend/src/types/card.ts index 9f37a9011e..46d3d79abe 100644 --- a/frontend/src/types/card.ts +++ b/frontend/src/types/card.ts @@ -6,6 +6,7 @@ import type { Contributor } from 'types/contributor' import type { HealthMetricsProps } from 'types/healthMetrics' import type { Icon } from 'types/icon' import type { Issue } from 'types/issue' +import type { Leader } from 'types/leader' import type { Level } from 'types/level' import type { Module } from 'types/mentorship' import type { Milestone } from 'types/milestone' @@ -44,6 +45,7 @@ export interface DetailsCardProps { description?: string details?: { label: string; value: string | JSX.Element }[] domains?: string[] + entityLeaders?: Leader[] entityKey?: string geolocationData?: Chapter[] healthMetricsData?: HealthMetricsProps[] diff --git a/frontend/src/types/chapter.ts b/frontend/src/types/chapter.ts index fe1e7f1bf8..7fb071b1f6 100644 --- a/frontend/src/types/chapter.ts +++ b/frontend/src/types/chapter.ts @@ -1,8 +1,10 @@ import type { Contributor } from 'types/contributor' +import type { Leader } from 'types/leader' export type Chapter = { _geoloc?: GeoLocation createdAt?: number + entityLeaders?: Leader[] geoLocation?: GeoLocation isActive?: boolean key: string diff --git a/frontend/src/types/leader.ts b/frontend/src/types/leader.ts new file mode 100644 index 0000000000..069d6b673a --- /dev/null +++ b/frontend/src/types/leader.ts @@ -0,0 +1,9 @@ +export type Leader = { + description: string + memberName: string + member: { + login: string + name: string + avatarUrl: string + } | null +} diff --git a/frontend/src/types/project.ts b/frontend/src/types/project.ts index 455286ab08..e737eae51e 100644 --- a/frontend/src/types/project.ts +++ b/frontend/src/types/project.ts @@ -1,6 +1,7 @@ import type { Contributor } from 'types/contributor' import type { HealthMetricsProps } from 'types/healthMetrics' import type { Issue } from 'types/issue' +import type { Leader } from 'types/leader' import type { Milestone } from 'types/milestone' import type { Organization } from 'types/organization' import type { PullRequest } from 'types/pullRequest' @@ -18,6 +19,7 @@ export type Project = { createdAt?: string contributorsCount?: number description?: string + entityLeaders?: Leader[] forksCount?: number healthMetricsList?: HealthMetricsProps[] isActive?: boolean From 87afa738ee04fd9a4a1bc59c7d5d19d876db5304 Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 17:14:50 +0530 Subject: [PATCH 03/10] add tests, Coderabbit and Sonar bot suggestions --- .../apps/owasp/api/internal/nodes/common.py | 2 +- .../e2e/pages/ChapterDetails.spec.ts | 6 +++ .../e2e/pages/ProjectDetails.spec.ts | 7 +++ .../unit/components/CardDetailsPage.test.tsx | 19 +++++++ .../unit/components/Leaders.test.tsx | 52 +++++++++++++++++++ .../unit/data/mockChapterDetailsData.ts | 12 +++++ .../unit/data/mockProjectDetailsData.ts | 12 +++++ .../unit/pages/ChapterDetails.test.tsx | 9 ++++ .../unit/pages/ProjectDetails.test.tsx | 9 ++++ frontend/src/app/about/page.tsx | 2 +- frontend/src/components/Leaders.tsx | 4 +- 11 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 frontend/__tests__/unit/components/Leaders.test.tsx diff --git a/backend/apps/owasp/api/internal/nodes/common.py b/backend/apps/owasp/api/internal/nodes/common.py index 85411adbbe..22dd259b7e 100644 --- a/backend/apps/owasp/api/internal/nodes/common.py +++ b/backend/apps/owasp/api/internal/nodes/common.py @@ -15,7 +15,7 @@ class GenericEntityNode(strawberry.relay.Node): @strawberry.field def entity_leaders(self) -> list[EntityMemberNode]: """Resolve entity leaders.""" - return self.entity_leaders + return list(self.entity_leaders.all()) @strawberry.field def leaders(self) -> list[str]: diff --git a/frontend/__tests__/e2e/pages/ChapterDetails.spec.ts b/frontend/__tests__/e2e/pages/ChapterDetails.spec.ts index e4bb465ea9..452aaa65f3 100644 --- a/frontend/__tests__/e2e/pages/ChapterDetails.spec.ts +++ b/frontend/__tests__/e2e/pages/ChapterDetails.spec.ts @@ -55,4 +55,10 @@ test.describe('Chapter Details Page', () => { await page.getByRole('button', { name: 'Show less' }).click() await expect(page.getByRole('button', { name: 'Show more' })).toBeVisible() }) + + test('should have leaders block', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'Leaders' })).toBeVisible() + await expect(page.getByText('Bob')).toBeVisible() + await expect(page.getByText('Chapter Leader')).toBeVisible() + }) }) diff --git a/frontend/__tests__/e2e/pages/ProjectDetails.spec.ts b/frontend/__tests__/e2e/pages/ProjectDetails.spec.ts index 91b7c4efaf..70eb9c1fa7 100644 --- a/frontend/__tests__/e2e/pages/ProjectDetails.spec.ts +++ b/frontend/__tests__/e2e/pages/ProjectDetails.spec.ts @@ -125,4 +125,11 @@ test.describe('Project Details Page', () => { await expect(page.getByText('Forks Trend')).toBeVisible() await expect(page.getByText('Days Since Last Commit and Release')).toBeVisible() }) + + test('should have leaders block', async ({ page }) => { + await expect(page.getByRole('heading', { name: 'Leaders' })).toBeVisible() + const userCard = page.getByRole('button', { name: /Alice/ }) + await expect(userCard.locator('h3')).toHaveText('Alice') + await expect(userCard.getByText('Project Leader')).toBeVisible() + }) }) diff --git a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx index 784c320cb7..d2531f4600 100644 --- a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx +++ b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx @@ -782,6 +782,25 @@ describe('CardDetailsPage', () => { expect(screen.getByTestId('leaders-list')).toBeInTheDocument() }) + it('renders Leaders component when entityLeaders are provided', () => { + const entityLeaders = [ + { + description: 'Project Leader', + memberName: 'Alice', + member: { + id: '1', + login: 'alice', + name: 'Alice', + avatarUrl: 'https://avatars.githubusercontent.com/u/12345?v=4', + }, + }, + ] + render() + expect(screen.getByText('Leaders')).toBeInTheDocument() + expect(screen.getByText('Alice')).toBeInTheDocument() + expect(screen.getByText('Project Leader')).toBeInTheDocument() + }) + it('capitalizes entity type in details title', () => { render() diff --git a/frontend/__tests__/unit/components/Leaders.test.tsx b/frontend/__tests__/unit/components/Leaders.test.tsx new file mode 100644 index 0000000000..d29de4992a --- /dev/null +++ b/frontend/__tests__/unit/components/Leaders.test.tsx @@ -0,0 +1,52 @@ +import { render, screen, fireEvent } from '@testing-library/react' +import { mockProjectDetailsData } from '@unit/data/mockProjectDetailsData' +import { useRouter } from 'next/navigation' +import Leaders from 'components/Leaders' + +jest.mock('next/navigation', () => ({ + useRouter: jest.fn(), +})) + +jest.mock('components/AnchorTitle', () => ({ + __esModule: true, + default: ({ title }: { title: string }) => {title}, +})) + +jest.mock('wrappers/FontAwesomeIconWrapper', () => ({ + __esModule: true, + default: () => , +})) + +describe('Leaders Component', () => { + const push = jest.fn() + beforeEach(() => { + ;(useRouter as jest.Mock).mockReturnValue({ push }) + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + it('renders a list of leaders', () => { + render() + + expect(screen.getByText('Leaders')).toBeInTheDocument() + expect(screen.getByText('Alice')).toBeInTheDocument() + expect(screen.getByText('Project Leader')).toBeInTheDocument() + }) + + it('renders the section title even with no leaders', () => { + render() + expect(screen.getByText('Leaders')).toBeInTheDocument() + expect(screen.queryByText('Alice')).not.toBeInTheDocument() + }) + + it('navigates to the correct page on button click', () => { + render() + + const viewProfileButton = screen.getByText('View Profile') + fireEvent.click(viewProfileButton) + + expect(push).toHaveBeenCalledWith('/members/alice') + }) +}) diff --git a/frontend/__tests__/unit/data/mockChapterDetailsData.ts b/frontend/__tests__/unit/data/mockChapterDetailsData.ts index f5963686d3..ba3edcd908 100644 --- a/frontend/__tests__/unit/data/mockChapterDetailsData.ts +++ b/frontend/__tests__/unit/data/mockChapterDetailsData.ts @@ -21,6 +21,18 @@ export const mockChapterDetailsData = { }, establishedYear: 2020, key: 'test-chapter', + entityLeaders: [ + { + description: 'Chapter Leader', + memberName: 'Bob', + member: { + id: '2', + login: 'bob', + name: 'Bob', + avatarUrl: 'https://avatars.githubusercontent.com/u/67890?v=4', + }, + }, + ], }, topContributors: Array.from({ length: 15 }, (_, i) => ({ avatarUrl: `https://avatars.githubusercontent.com/avatar${i + 1}.jpg`, diff --git a/frontend/__tests__/unit/data/mockProjectDetailsData.ts b/frontend/__tests__/unit/data/mockProjectDetailsData.ts index 9d9c195022..d1957eeebb 100644 --- a/frontend/__tests__/unit/data/mockProjectDetailsData.ts +++ b/frontend/__tests__/unit/data/mockProjectDetailsData.ts @@ -20,6 +20,18 @@ export const mockProjectDetailsData = { key: 'example-project', languages: ['Python', 'GraphQL', 'JavaScript'], leaders: ['alice', 'bob'], + entityLeaders: [ + { + description: 'Project Leader', + memberName: 'Alice', + member: { + id: '1', + login: 'alice', + name: 'Alice', + avatarUrl: 'https://avatars.githubusercontent.com/u/12345?v=4', + }, + }, + ], level: 'Lab', name: 'Test Project', recentIssues: [ diff --git a/frontend/__tests__/unit/pages/ChapterDetails.test.tsx b/frontend/__tests__/unit/pages/ChapterDetails.test.tsx index 04ee5ab1bf..722bc914f9 100644 --- a/frontend/__tests__/unit/pages/ChapterDetails.test.tsx +++ b/frontend/__tests__/unit/pages/ChapterDetails.test.tsx @@ -130,4 +130,13 @@ describe('chapterDetailsPage Component', () => { expect(screen.getByText(`Sponsor ${mockChapterDetailsData.chapter.name}`)).toBeInTheDocument() }) }) + + test('renders leaders block from entityLeaders', async () => { + render() + await waitFor(() => { + expect(screen.getByText('Leaders')).toBeInTheDocument() + expect(screen.getByText('Bob')).toBeInTheDocument() + expect(screen.getByText('Chapter Leader')).toBeInTheDocument() + }) + }) }) diff --git a/frontend/__tests__/unit/pages/ProjectDetails.test.tsx b/frontend/__tests__/unit/pages/ProjectDetails.test.tsx index 760f06c579..ece21e35ca 100644 --- a/frontend/__tests__/unit/pages/ProjectDetails.test.tsx +++ b/frontend/__tests__/unit/pages/ProjectDetails.test.tsx @@ -289,4 +289,13 @@ describe('ProjectDetailsPage', () => { expect(screen.getByText(`Sponsor ${mockProjectDetailsData.project.name}`)).toBeInTheDocument() }) }) + + test('renders leaders block from entityLeaders', async () => { + render() + await waitFor(() => { + expect(screen.getByText('Leaders')).toBeInTheDocument() + expect(screen.getByText('Alice')).toBeInTheDocument() + expect(screen.getByText('Project Leader')).toBeInTheDocument() + }) + }) }) diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index 7782694852..efc3afd80d 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -62,7 +62,7 @@ const useLeadersData = () => { const isLoading = loading1 || loading2 || loading3 const formattedLeaders = [leader1Data?.user, leader2Data?.user, leader3Data?.user] - .filter((user) => user) + .filter(Boolean) .map((user) => ({ description: leaders[user.login], memberName: user.name || user.login, diff --git a/frontend/src/components/Leaders.tsx b/frontend/src/components/Leaders.tsx index af8dc656c9..9596ffe456 100644 --- a/frontend/src/components/Leaders.tsx +++ b/frontend/src/components/Leaders.tsx @@ -25,9 +25,9 @@ const Leaders: React.FC = ({ users }) => { return ( }>
- {users.map((user, index) => ( + {users.map((user) => ( , From 5f4839cd9f9e9f9b3225cbeb379d9b13b54cd88f Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 17:43:25 +0530 Subject: [PATCH 04/10] Update code --- .../apps/owasp/api/internal/nodes/common.py | 4 +-- frontend/__tests__/unit/pages/About.test.tsx | 33 +++++++++++++++++++ frontend/src/app/about/page.tsx | 24 ++++++++++++-- frontend/src/components/Leaders.tsx | 2 +- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/backend/apps/owasp/api/internal/nodes/common.py b/backend/apps/owasp/api/internal/nodes/common.py index 22dd259b7e..1e2c1358d0 100644 --- a/backend/apps/owasp/api/internal/nodes/common.py +++ b/backend/apps/owasp/api/internal/nodes/common.py @@ -2,9 +2,7 @@ import strawberry -from apps.github.api.internal.nodes.repository_contributor import ( - RepositoryContributorNode, -) +from apps.github.api.internal.nodes.repository_contributor import RepositoryContributorNode from apps.owasp.api.internal.nodes.entity_member import EntityMemberNode diff --git a/frontend/__tests__/unit/pages/About.test.tsx b/frontend/__tests__/unit/pages/About.test.tsx index 199cbd99fb..93cd2d96e1 100644 --- a/frontend/__tests__/unit/pages/About.test.tsx +++ b/frontend/__tests__/unit/pages/About.test.tsx @@ -553,4 +553,37 @@ describe('About Component', () => { expect(screen.getByText('Timeline description 1')).toBeInTheDocument() expect(screen.getByText('Timeline description 2')).toBeInTheDocument() }) + + test('triggers toaster error when GraphQL request fails for a leader', async () => { + ;(useQuery as unknown as jest.Mock).mockImplementation((query, options) => { + if (query === GetLeaderDataDocument && options?.variables?.key === 'arkid15r') { + return { loading: false, data: null, error: new Error('GraphQL error for leader') } + } + if (query === GetProjectMetadataDocument) { + return mockProjectData + } + if (query === GetTopContributorsDocument) { + return mockTopContributorsData + } + if (query === GetLeaderDataDocument) { + return mockUserData(options?.variables?.key) + } + return { loading: true } + }) + + await act(async () => { + render() + }) + + await waitFor(() => { + expect(addToast).toHaveBeenCalledWith({ + color: 'danger', + description: 'GraphQL error for leader', + shouldShowTimeoutProgress: true, + timeout: 5000, + title: 'Server Error', + variant: 'solid', + }) + }) + }) }) diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index efc3afd80d..79df61df0c 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -49,18 +49,36 @@ const leaders = { } const useLeadersData = () => { - const { data: leader1Data, loading: loading1 } = useQuery(GetLeaderDataDocument, { + const { + data: leader1Data, + loading: loading1, + error: error1, + } = useQuery(GetLeaderDataDocument, { variables: { key: 'arkid15r' }, }) - const { data: leader2Data, loading: loading2 } = useQuery(GetLeaderDataDocument, { + const { + data: leader2Data, + loading: loading2, + error: error2, + } = useQuery(GetLeaderDataDocument, { variables: { key: 'kasya' }, }) - const { data: leader3Data, loading: loading3 } = useQuery(GetLeaderDataDocument, { + const { + data: leader3Data, + loading: loading3, + error: error3, + } = useQuery(GetLeaderDataDocument, { variables: { key: 'mamicidal' }, }) const isLoading = loading1 || loading2 || loading3 + useEffect(() => { + if (error1) handleAppError(error1) + if (error2) handleAppError(error2) + if (error3) handleAppError(error3) + }, [error1, error2, error3]) + const formattedLeaders = [leader1Data?.user, leader2Data?.user, leader3Data?.user] .filter(Boolean) .map((user) => ({ diff --git a/frontend/src/components/Leaders.tsx b/frontend/src/components/Leaders.tsx index 9596ffe456..ecfeeb2457 100644 --- a/frontend/src/components/Leaders.tsx +++ b/frontend/src/components/Leaders.tsx @@ -34,7 +34,7 @@ const Leaders: React.FC = ({ users }) => { label: 'View Profile', onclick: () => handleButtonClick(user), }} - className="h-64 w-42 bg-inherit" + className="h-64 w-44 bg-inherit" description={user.description} name={user.member?.name || user.memberName} /> From e638ef50d4e3a741836b0d23631dacb5e08326cc Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 17:49:16 +0530 Subject: [PATCH 05/10] sort alphabetically --- backend/apps/owasp/api/internal/nodes/entity_member.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/apps/owasp/api/internal/nodes/entity_member.py b/backend/apps/owasp/api/internal/nodes/entity_member.py index df866131a2..135a51080d 100644 --- a/backend/apps/owasp/api/internal/nodes/entity_member.py +++ b/backend/apps/owasp/api/internal/nodes/entity_member.py @@ -10,13 +10,13 @@ @strawberry_django.type( EntityMember, fields=[ - "role", - "member_name", - "member_email", "description", "is_active", "is_reviewed", + "member_email", + "member_name", "order", + "role", ], ) class EntityMemberNode(strawberry.relay.Node): From c523c7b9dd92b39e83fa4531d1d1bc6db303e158 Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 18:02:46 +0530 Subject: [PATCH 06/10] use fontawesome icon --- frontend/src/components/Leaders.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Leaders.tsx b/frontend/src/components/Leaders.tsx index ecfeeb2457..88fb2c6dfc 100644 --- a/frontend/src/components/Leaders.tsx +++ b/frontend/src/components/Leaders.tsx @@ -1,4 +1,4 @@ -import { faPersonWalkingArrowRight } from '@fortawesome/free-solid-svg-icons' +import { faPersonWalkingArrowRight, faRightToBracket } from '@fortawesome/free-solid-svg-icons' import { useRouter } from 'next/navigation' import React from 'react' import FontAwesomeIconWrapper from 'wrappers/FontAwesomeIconWrapper' @@ -30,7 +30,7 @@ const Leaders: React.FC = ({ users }) => { key={user.member?.login || user.memberName} avatar={user.member?.avatarUrl} button={{ - icon: , + icon: , label: 'View Profile', onclick: () => handleButtonClick(user), }} From e31ed65c3f7b024d3f215175981bf708c5fb4376 Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 18:05:03 +0530 Subject: [PATCH 07/10] Update docstring --- backend/apps/owasp/api/internal/nodes/entity_member.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/apps/owasp/api/internal/nodes/entity_member.py b/backend/apps/owasp/api/internal/nodes/entity_member.py index 135a51080d..2efb94e7d5 100644 --- a/backend/apps/owasp/api/internal/nodes/entity_member.py +++ b/backend/apps/owasp/api/internal/nodes/entity_member.py @@ -1,4 +1,4 @@ -"""OWASP app entity member node.""" +"""OWASP app entity member GraphQL node.""" import strawberry import strawberry_django From 218efdbc83cf26b272d655a4b5661bfc94513ccd Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 18:28:28 +0530 Subject: [PATCH 08/10] Update code --- frontend/src/app/about/page.tsx | 88 ++++++++++++++++----------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index 79df61df0c..666ebb26ab 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -48,48 +48,6 @@ const leaders = { mamicidal: 'CISSP', } -const useLeadersData = () => { - const { - data: leader1Data, - loading: loading1, - error: error1, - } = useQuery(GetLeaderDataDocument, { - variables: { key: 'arkid15r' }, - }) - const { - data: leader2Data, - loading: loading2, - error: error2, - } = useQuery(GetLeaderDataDocument, { - variables: { key: 'kasya' }, - }) - const { - data: leader3Data, - loading: loading3, - error: error3, - } = useQuery(GetLeaderDataDocument, { - variables: { key: 'mamicidal' }, - }) - - const isLoading = loading1 || loading2 || loading3 - - useEffect(() => { - if (error1) handleAppError(error1) - if (error2) handleAppError(error2) - if (error3) handleAppError(error3) - }, [error1, error2, error3]) - - const formattedLeaders = [leader1Data?.user, leader2Data?.user, leader3Data?.user] - .filter(Boolean) - .map((user) => ({ - description: leaders[user.login], - memberName: user.name || user.login, - member: user, - })) - - return { formattedLeaders, isLoading } -} - const projectKey = 'nest' const About = () => { @@ -112,7 +70,7 @@ const About = () => { } ) - const { formattedLeaders, isLoading: leadersLoading } = useLeadersData() + const { leadersData, isLoading: leadersLoading } = useLeadersData() const [projectMetadata, setProjectMetadata] = useState(null) const [topContributors, setTopContributors] = useState([]) @@ -183,7 +141,7 @@ const About = () => {
- + {topContributors && ( { ) } +const useLeadersData = () => { + const { + data: leader1Data, + loading: loading1, + error: error1, + } = useQuery(GetLeaderDataDocument, { + variables: { key: 'arkid15r' }, + }) + const { + data: leader2Data, + loading: loading2, + error: error2, + } = useQuery(GetLeaderDataDocument, { + variables: { key: 'kasya' }, + }) + const { + data: leader3Data, + loading: loading3, + error: error3, + } = useQuery(GetLeaderDataDocument, { + variables: { key: 'mamicidal' }, + }) + + const isLoading = loading1 || loading2 || loading3 + + useEffect(() => { + if (error1) handleAppError(error1) + if (error2) handleAppError(error2) + if (error3) handleAppError(error3) + }, [error1, error2, error3]) + + const leadersData = [leader1Data?.user, leader2Data?.user, leader3Data?.user] + .filter(Boolean) + .map((user) => ({ + description: leaders[user.login], + memberName: user.name || user.login, + member: user, + })) + + return { leadersData, isLoading } +} + export default About From 269daf75b5203ff0d49642a0a86a981131d8a984 Mon Sep 17 00:00:00 2001 From: Rudransh Shrivastava Date: Fri, 10 Oct 2025 21:36:45 +0530 Subject: [PATCH 09/10] sort alphabetically --- .../unit/data/mockChapterDetailsData.ts | 4 ++-- .../unit/data/mockProjectDetailsData.ts | 24 +++++++++---------- frontend/src/server/queries/chapterQueries.ts | 22 ++++++++--------- frontend/src/server/queries/projectQueries.ts | 12 +++++----- .../__generated__/chapterQueries.generated.ts | 4 ++-- .../__generated__/projectQueries.generated.ts | 2 +- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/frontend/__tests__/unit/data/mockChapterDetailsData.ts b/frontend/__tests__/unit/data/mockChapterDetailsData.ts index ba3edcd908..067e7aaf67 100644 --- a/frontend/__tests__/unit/data/mockChapterDetailsData.ts +++ b/frontend/__tests__/unit/data/mockChapterDetailsData.ts @@ -19,8 +19,6 @@ export const mockChapterDetailsData = { lat: 23.2584857, lng: 77.401989, }, - establishedYear: 2020, - key: 'test-chapter', entityLeaders: [ { description: 'Chapter Leader', @@ -33,6 +31,8 @@ export const mockChapterDetailsData = { }, }, ], + establishedYear: 2020, + key: 'test-chapter', }, topContributors: Array.from({ length: 15 }, (_, i) => ({ avatarUrl: `https://avatars.githubusercontent.com/avatar${i + 1}.jpg`, diff --git a/frontend/__tests__/unit/data/mockProjectDetailsData.ts b/frontend/__tests__/unit/data/mockProjectDetailsData.ts index d1957eeebb..39bd7cf5fb 100644 --- a/frontend/__tests__/unit/data/mockProjectDetailsData.ts +++ b/frontend/__tests__/unit/data/mockProjectDetailsData.ts @@ -1,6 +1,18 @@ export const mockProjectDetailsData = { project: { contributorsCount: 1200, + entityLeaders: [ + { + description: 'Project Leader', + memberName: 'Alice', + member: { + id: '1', + login: 'alice', + name: 'Alice', + avatarUrl: 'https://avatars.githubusercontent.com/u/12345?v=4', + }, + }, + ], forksCount: 10, healthMetricsList: [ { @@ -20,18 +32,6 @@ export const mockProjectDetailsData = { key: 'example-project', languages: ['Python', 'GraphQL', 'JavaScript'], leaders: ['alice', 'bob'], - entityLeaders: [ - { - description: 'Project Leader', - memberName: 'Alice', - member: { - id: '1', - login: 'alice', - name: 'Alice', - avatarUrl: 'https://avatars.githubusercontent.com/u/12345?v=4', - }, - }, - ], level: 'Lab', name: 'Test Project', recentIssues: [ diff --git a/frontend/src/server/queries/chapterQueries.ts b/frontend/src/server/queries/chapterQueries.ts index 478be9d260..0035194da8 100644 --- a/frontend/src/server/queries/chapterQueries.ts +++ b/frontend/src/server/queries/chapterQueries.ts @@ -4,6 +4,17 @@ export const GET_CHAPTER_DATA = gql` query GetChapterData($key: String!) { chapter(key: $key) { id + entityLeaders { + id + description + memberName + member { + id + login + name + avatarUrl + } + } geoLocation { lat lng @@ -17,17 +28,6 @@ export const GET_CHAPTER_DATA = gql` summary updatedAt url - entityLeaders { - id - description - memberName - member { - id - login - name - avatarUrl - } - } } topContributors(chapter: $key) { id diff --git a/frontend/src/server/queries/projectQueries.ts b/frontend/src/server/queries/projectQueries.ts index 503c6bcbff..f51d82c905 100644 --- a/frontend/src/server/queries/projectQueries.ts +++ b/frontend/src/server/queries/projectQueries.ts @@ -5,12 +5,6 @@ export const GET_PROJECT_DATA = gql` project(key: $key) { id contributorsCount - forksCount - issuesCount - isActive - key - languages - leaders entityLeaders { id description @@ -22,6 +16,12 @@ export const GET_PROJECT_DATA = gql` avatarUrl } } + forksCount + issuesCount + isActive + key + languages + leaders level name healthMetricsList(limit: 30) { diff --git a/frontend/src/types/__generated__/chapterQueries.generated.ts b/frontend/src/types/__generated__/chapterQueries.generated.ts index 32720a4000..e24187a4e3 100644 --- a/frontend/src/types/__generated__/chapterQueries.generated.ts +++ b/frontend/src/types/__generated__/chapterQueries.generated.ts @@ -6,7 +6,7 @@ export type GetChapterDataQueryVariables = Types.Exact<{ }>; -export type GetChapterDataQuery = { chapter: { __typename: 'ChapterNode', id: string, isActive: boolean, key: string, name: string, region: string, relatedUrls: Array, suggestedLocation: string | null, summary: string, updatedAt: number, url: string, geoLocation: { __typename: 'GeoLocationType', lat: number, lng: number } | null, entityLeaders: Array<{ __typename: 'EntityMemberNode', id: string, description: string, memberName: string, member: { __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string } | null }> } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; +export type GetChapterDataQuery = { chapter: { __typename: 'ChapterNode', id: string, isActive: boolean, key: string, name: string, region: string, relatedUrls: Array, suggestedLocation: string | null, summary: string, updatedAt: number, url: string, entityLeaders: Array<{ __typename: 'EntityMemberNode', id: string, description: string, memberName: string, member: { __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string } | null }>, geoLocation: { __typename: 'GeoLocationType', lat: number, lng: number } | null } | null, topContributors: Array<{ __typename: 'RepositoryContributorNode', id: string, avatarUrl: string, login: string, name: string }> }; export type GetChapterMetadataQueryVariables = Types.Exact<{ key: Types.Scalars['String']['input']; @@ -16,5 +16,5 @@ export type GetChapterMetadataQueryVariables = Types.Exact<{ export type GetChapterMetadataQuery = { chapter: { __typename: 'ChapterNode', id: string, name: string, summary: string } | null }; -export const GetChapterDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"geoLocation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lng"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"region"}},{"kind":"Field","name":{"kind":"Name","value":"relatedUrls"}},{"kind":"Field","name":{"kind":"Name","value":"suggestedLocation"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"chapter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetChapterDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"geoLocation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lat"}},{"kind":"Field","name":{"kind":"Name","value":"lng"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"region"}},{"kind":"Field","name":{"kind":"Name","value":"relatedUrls"}},{"kind":"Field","name":{"kind":"Name","value":"suggestedLocation"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"chapter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const GetChapterMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChapterMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/types/__generated__/projectQueries.generated.ts b/frontend/src/types/__generated__/projectQueries.generated.ts index 294b4d02b4..7d9ac11b18 100644 --- a/frontend/src/types/__generated__/projectQueries.generated.ts +++ b/frontend/src/types/__generated__/projectQueries.generated.ts @@ -33,7 +33,7 @@ export type SearchProjectNamesQueryVariables = Types.Exact<{ export type SearchProjectNamesQuery = { searchProjects: Array<{ __typename: 'ProjectNode', id: string, name: string }> }; -export const GetProjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"languages"}},{"kind":"Field","name":{"kind":"Name","value":"leaders"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"level"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"healthMetricsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"30"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"openPullRequestsCount"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"unassignedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"unansweredIssuesCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentIssues"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentReleases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"tagName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"}}]}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"subscribersCount"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositoriesCount"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"topics"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentPullRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetProjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"entityLeaders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"memberName"}},{"kind":"Field","name":{"kind":"Name","value":"member"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"languages"}},{"kind":"Field","name":{"kind":"Name","value":"leaders"}},{"kind":"Field","name":{"kind":"Name","value":"level"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"healthMetricsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"30"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastCommitDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDays"}},{"kind":"Field","name":{"kind":"Name","value":"lastReleaseDaysRequirement"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"openPullRequestsCount"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"unassignedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"unansweredIssuesCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentIssues"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentReleases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"publishedAt"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"tagName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"}}]}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"subscribersCount"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"repositoriesCount"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"topics"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"recentPullRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const GetProjectMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProjectMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"contributorsCount"}},{"kind":"Field","name":{"kind":"Name","value":"forksCount"}},{"kind":"Field","name":{"kind":"Name","value":"issuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"starsCount"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"recentMilestones"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"25"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"progress"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetTopContributorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTopContributors"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"excludedUsernames"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hasFullName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"topContributors"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"excludedUsernames"},"value":{"kind":"Variable","name":{"kind":"Name","value":"excludedUsernames"}}},{"kind":"Argument","name":{"kind":"Name","value":"hasFullName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasFullName"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"project"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"login"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const SearchProjectNamesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchProjectNames"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchProjects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file From f7c3fa2ff6680faab2d0a2d38db48625d6247d27 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 12 Oct 2025 11:29:20 -0700 Subject: [PATCH 10/10] Update code --- .../apps/owasp/api/internal/nodes/common.py | 2 +- backend/apps/owasp/models/common.py | 20 ++++++++++--------- backend/apps/owasp/models/project.py | 11 ++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/backend/apps/owasp/api/internal/nodes/common.py b/backend/apps/owasp/api/internal/nodes/common.py index 1e2c1358d0..a692265fad 100644 --- a/backend/apps/owasp/api/internal/nodes/common.py +++ b/backend/apps/owasp/api/internal/nodes/common.py @@ -13,7 +13,7 @@ class GenericEntityNode(strawberry.relay.Node): @strawberry.field def entity_leaders(self) -> list[EntityMemberNode]: """Resolve entity leaders.""" - return list(self.entity_leaders.all()) + return self.entity_leaders @strawberry.field def leaders(self) -> list[str]: diff --git a/backend/apps/owasp/models/common.py b/backend/apps/owasp/models/common.py index 49b2ed254a..64208aa31e 100644 --- a/backend/apps/owasp/models/common.py +++ b/backend/apps/owasp/models/common.py @@ -89,6 +89,17 @@ class Meta: blank=True, ) + @property + def entity_leaders(self) -> models.QuerySet[EntityMember]: + """Return entity's leaders.""" + return EntityMember.objects.filter( + entity_id=self.id, + entity_type=ContentType.objects.get_for_model(self.__class__), + is_active=True, + is_reviewed=True, + role=EntityMember.Role.LEADER, + ).order_by("order") + @property def github_url(self) -> str: """Get GitHub URL.""" @@ -114,15 +125,6 @@ def info_md_url(self) -> str | None: else None ) - @property - def entity_leaders(self) -> models.QuerySet[EntityMember]: - """Return entity's leaders.""" - return EntityMember.objects.filter( - entity_type=ContentType.objects.get_for_model(self.__class__), - entity_id=self.pk, - role=EntityMember.Role.LEADER, - ) - @property def leaders_md_url(self) -> str | None: """Return entity's raw leaders.md GitHub URL.""" diff --git a/backend/apps/owasp/models/project.py b/backend/apps/owasp/models/project.py index 4a67afce6b..b377900bb7 100644 --- a/backend/apps/owasp/models/project.py +++ b/backend/apps/owasp/models/project.py @@ -4,6 +4,7 @@ import datetime from functools import lru_cache +from typing import TYPE_CHECKING from django.contrib.contenttypes.fields import GenericRelation from django.db import models @@ -27,6 +28,11 @@ from apps.owasp.models.mixins.project import ProjectIndexMixin from apps.owasp.models.project_health_metrics import ProjectHealthMetrics +if TYPE_CHECKING: + from apps.owasp.models.entity_member import EntityMember + +MAX_LEADERS_COUNT = 5 + class Project( BulkSaveModel, @@ -124,6 +130,11 @@ def __str__(self) -> str: """Project human readable representation.""" return f"{self.name or self.key}" + @property + def entity_leaders(self) -> models.QuerySet[EntityMember]: + """Return project leaders.""" + return super().entity_leaders[:MAX_LEADERS_COUNT] + @property def health_score(self) -> float | None: """Return project health score."""