diff --git a/backend/apps/mentorship/api/internal/nodes/program.py b/backend/apps/mentorship/api/internal/nodes/program.py index 463caa076f..bee27227ec 100644 --- a/backend/apps/mentorship/api/internal/nodes/program.py +++ b/backend/apps/mentorship/api/internal/nodes/program.py @@ -4,6 +4,8 @@ import strawberry +from apps.github.api.internal.nodes.milestone import MilestoneNode # noqa: TC001 +from apps.github.models.milestone import Milestone from apps.mentorship.api.internal.nodes.enum import ( ExperienceLevelEnum, ProgramStatusEnum, @@ -33,6 +35,19 @@ def admins(self) -> list[MentorNode] | None: """Get the list of program administrators.""" return self.admins.all() + @strawberry.field + def recent_milestones(self) -> list["MilestoneNode"]: + """Get the list of recent milestones for the program.""" + project_ids = self.modules.values_list("project_id", flat=True) + + return ( + Milestone.open_milestones.filter(repository__project__in=project_ids) + .select_related("repository__organization", "author") + .prefetch_related("labels") + .order_by("-created_at") + .distinct() + ) + @strawberry.type class PaginatedPrograms: diff --git a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx index b779fa3623..0f47545da5 100644 --- a/frontend/__tests__/unit/components/CardDetailsPage.test.tsx +++ b/frontend/__tests__/unit/components/CardDetailsPage.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, cleanup } from '@testing-library/react' +import { render, screen, cleanup, fireEvent } from '@testing-library/react' import React from 'react' import '@testing-library/jest-dom' import { FaCode, FaTags } from 'react-icons/fa6' @@ -1701,4 +1701,103 @@ describe('CardDetailsPage', () => { ) }) }) + + describe('Program Milestones Display', () => { + const createMilestones = (count: number) => { + const milestones = [] + for (let i = 0; i < count; i++) { + milestones.push({ + author: mockUser, + body: `Milestone description ${i + 1}`, + closedIssuesCount: 5, + createdAt: new Date(Date.now() - 10000000).toISOString(), + openIssuesCount: 2, + repositoryName: `test-repo-${i}`, + organizationName: 'test-org', + state: 'open', + title: `Milestone ${i + 1}`, + url: `https://github.com/test/project/milestone/${i + 1}`, + }) + } + return milestones + } + + it('renders only first 4 milestones initially for program type', () => { + const manyMilestones = createMilestones(6) + const programProps: DetailsCardProps = { + ...defaultProps, + type: 'program' as const, + recentMilestones: manyMilestones, + modules: [], + } + + render() + + expect(screen.getByText('Recent Milestones')).toBeInTheDocument() + + expect(screen.getByText('Milestone 1')).toBeInTheDocument() + expect(screen.getByText('Milestone 4')).toBeInTheDocument() + + expect(screen.queryByText('Milestone 5')).not.toBeInTheDocument() + expect(screen.queryByText('Milestone 6')).not.toBeInTheDocument() + + expect(screen.getByText(/Show more/i)).toBeInTheDocument() + }) + + it('expands to show all milestones when "Show more" is clicked', () => { + const manyMilestones = createMilestones(6) + const programProps: DetailsCardProps = { + ...defaultProps, + type: 'program' as const, + recentMilestones: manyMilestones, + modules: [], + } + + render() + + const showMoreBtn = screen.getByText(/Show more/i) + fireEvent.click(showMoreBtn) + + expect(screen.getByText('Milestone 5')).toBeInTheDocument() + expect(screen.getByText('Milestone 6')).toBeInTheDocument() + + expect(screen.getByText(/Show less/i)).toBeInTheDocument() + }) + + it('collapses back to 4 milestones when "Show less" is clicked', () => { + const manyMilestones = createMilestones(6) + const programProps: DetailsCardProps = { + ...defaultProps, + type: 'program' as const, + recentMilestones: manyMilestones, + modules: [], + } + + render() + + fireEvent.click(screen.getByText(/Show more/i)) + expect(screen.getByText('Milestone 5')).toBeInTheDocument() + + fireEvent.click(screen.getByText(/Show less/i)) + + expect(screen.queryByText('Milestone 5')).not.toBeInTheDocument() + expect(screen.getByText(/Show more/i)).toBeInTheDocument() + }) + + it('does not show toggle button if milestones <= 4', () => { + const fewMilestones = createMilestones(4) + const programProps: DetailsCardProps = { + ...defaultProps, + type: 'program' as const, + recentMilestones: fewMilestones, + modules: [], + } + + render() + + expect(screen.getByText('Milestone 1')).toBeInTheDocument() + expect(screen.getByText('Milestone 4')).toBeInTheDocument() + expect(screen.queryByText(/Show more/i)).not.toBeInTheDocument() + }) + }) }) diff --git a/frontend/src/app/mentorship/programs/[programKey]/page.tsx b/frontend/src/app/mentorship/programs/[programKey]/page.tsx index 4283467f6f..9f4f571c81 100644 --- a/frontend/src/app/mentorship/programs/[programKey]/page.tsx +++ b/frontend/src/app/mentorship/programs/[programKey]/page.tsx @@ -66,9 +66,11 @@ const ProgramDetailsPage = () => { return ( const showPullRequestsAndReleases = (type: CardType): boolean => ['organization', 'project', 'repository', 'user'].includes(type) +const MILESTONE_LIMIT = 4 + const DetailsCard = ({ description, details, @@ -100,6 +114,7 @@ const DetailsCard = ({ userSummary, }: DetailsCardProps) => { const { data: session } = useSession() as { data: ExtendedSession | null } + const [showAllMilestones, setShowAllMilestones] = useState(false) // compute styles based on type prop const typeStylesMap = { @@ -366,6 +381,97 @@ const DetailsCard = ({ )} + {type === 'program' && recentMilestones && recentMilestones.length > 0 && ( + }> + + {recentMilestones + .slice(0, showAllMilestones ? recentMilestones.length : MILESTONE_LIMIT) + .map((milestone, index) => ( + + + + {showAvatar && milestone?.author?.login && milestone?.author?.avatarUrl && ( + + + + + + )} + + {milestone?.url ? ( + + + + ) : ( + + )} + + + + + + + {formatDate(milestone.createdAt)} + + + + {milestone.closedIssuesCount} closed + + + + {milestone.openIssuesCount} open + + {milestone?.repositoryName && milestone?.organizationName && ( + + + + + + + )} + + + + + ))} + + {recentMilestones.length > MILESTONE_LIMIT && ( + setShowAllMilestones(!showAllMilestones)} /> + )} + + )} {IS_PROJECT_HEALTH_ENABLED && type === 'project' && healthMetricsData.length > 0 && ( )} diff --git a/frontend/src/server/queries/programsQueries.ts b/frontend/src/server/queries/programsQueries.ts index ee2796b1c7..265ce7b71e 100644 --- a/frontend/src/server/queries/programsQueries.ts +++ b/frontend/src/server/queries/programsQueries.ts @@ -62,6 +62,23 @@ export const GET_PROGRAM_AND_MODULES = gql` name avatarUrl } + recentMilestones { + id + title + state + openIssuesCount + closedIssuesCount + createdAt + repositoryName + organizationName + url + author { + id + login + name + avatarUrl + } + } } getProgramModules(programKey: $programKey) { id diff --git a/frontend/src/types/__generated__/graphql.ts b/frontend/src/types/__generated__/graphql.ts index fcc6113f29..30ae04fc8f 100644 --- a/frontend/src/types/__generated__/graphql.ts +++ b/frontend/src/types/__generated__/graphql.ts @@ -530,6 +530,7 @@ export type ProgramNode = { key: Scalars['String']['output']; menteesLimit?: Maybe; name: Scalars['String']['output']; + recentMilestones: Array; startedAt: Scalars['DateTime']['output']; status: ProgramStatusEnum; tags?: Maybe>; diff --git a/frontend/src/types/__generated__/programsQueries.generated.ts b/frontend/src/types/__generated__/programsQueries.generated.ts index c01cfa8261..d9a2162bad 100644 --- a/frontend/src/types/__generated__/programsQueries.generated.ts +++ b/frontend/src/types/__generated__/programsQueries.generated.ts @@ -22,7 +22,7 @@ export type GetProgramAndModulesQueryVariables = Types.Exact<{ }>; -export type GetProgramAndModulesQuery = { getProgram: { __typename: 'ProgramNode', id: string, key: string, name: string, description: string, status: Types.ProgramStatusEnum, menteesLimit: number | null, experienceLevels: Array | null, startedAt: any, endedAt: any, domains: Array | null, tags: Array | null, admins: Array<{ __typename: 'MentorNode', id: string, login: string, name: string, avatarUrl: string }> | null } | null, getProgramModules: Array<{ __typename: 'ModuleNode', id: string, key: string, name: string, description: string, experienceLevel: Types.ExperienceLevelEnum, startedAt: any, endedAt: any, domains: Array | null, tags: Array | null, labels: Array | null, mentors: Array<{ __typename: 'MentorNode', id: string, login: string, name: string, avatarUrl: string }>, mentees: Array<{ __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string }> }> }; +export type GetProgramAndModulesQuery = { getProgram: { __typename: 'ProgramNode', id: string, key: string, name: string, description: string, status: Types.ProgramStatusEnum, menteesLimit: number | null, experienceLevels: Array | null, startedAt: any, endedAt: any, domains: Array | null, tags: Array | null, admins: Array<{ __typename: 'MentorNode', id: string, login: string, name: string, avatarUrl: string }> | null, recentMilestones: Array<{ __typename: 'MilestoneNode', id: string, title: string, state: string, openIssuesCount: number, closedIssuesCount: number, createdAt: any, repositoryName: string | null, organizationName: string | null, url: string, author: { __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string } | null }> } | null, getProgramModules: Array<{ __typename: 'ModuleNode', id: string, key: string, name: string, description: string, experienceLevel: Types.ExperienceLevelEnum, startedAt: any, endedAt: any, domains: Array | null, tags: Array | null, labels: Array | null, mentors: Array<{ __typename: 'MentorNode', id: string, login: string, name: string, avatarUrl: string }>, mentees: Array<{ __typename: 'UserNode', id: string, login: string, name: string, avatarUrl: string }> }> }; export type GetProgramAdminDetailsQueryVariables = Types.Exact<{ programKey: Types.Scalars['String']['input']; @@ -34,5 +34,5 @@ export type GetProgramAdminDetailsQuery = { getProgram: { __typename: 'ProgramNo export const GetMyProgramsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMyPrograms"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myPrograms"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentPage"}},{"kind":"Field","name":{"kind":"Name","value":"totalPages"}},{"kind":"Field","name":{"kind":"Name","value":"programs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"userRole"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetProgramDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProgramDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getProgram"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"menteesLimit"}},{"kind":"Field","name":{"kind":"Name","value":"experienceLevels"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"domains"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}},{"kind":"Field","name":{"kind":"Name","value":"admins"},"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"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetProgramAndModulesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProgramAndModules"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getProgram"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"menteesLimit"}},{"kind":"Field","name":{"kind":"Name","value":"experienceLevels"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"domains"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}},{"kind":"Field","name":{"kind":"Name","value":"admins"},"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":"getProgramModules"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"experienceLevel"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"domains"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}},{"kind":"Field","name":{"kind":"Name","value":"labels"}},{"kind":"Field","name":{"kind":"Name","value":"mentors"},"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":"mentees"},"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"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetProgramAndModulesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProgramAndModules"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getProgram"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"menteesLimit"}},{"kind":"Field","name":{"kind":"Name","value":"experienceLevels"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"domains"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}},{"kind":"Field","name":{"kind":"Name","value":"admins"},"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":"recentMilestones"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"openIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"closedIssuesCount"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"repositoryName"}},{"kind":"Field","name":{"kind":"Name","value":"organizationName"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"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":"getProgramModules"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"experienceLevel"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"domains"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}},{"kind":"Field","name":{"kind":"Name","value":"labels"}},{"kind":"Field","name":{"kind":"Name","value":"mentors"},"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":"mentees"},"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"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetProgramAdminDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProgramAdminDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getProgram"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"programKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"programKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"admins"},"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"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/types/mentorship.ts b/frontend/src/types/mentorship.ts index d97c93aba1..71fbbb18e7 100644 --- a/frontend/src/types/mentorship.ts +++ b/frontend/src/types/mentorship.ts @@ -1,5 +1,6 @@ import type { Contributor } from 'types/contributor' import type { Issue } from 'types/issue' +import type { Milestone } from 'types/milestone' // eslint-disable-next-line no-restricted-imports import { ExperienceLevelEnum, ProgramStatusEnum } from './__generated__/graphql' @@ -19,6 +20,7 @@ export type Program = { userRole?: string admins?: Contributor[] modules?: Module[] + recentMilestones?: Milestone[] } export type ProgramList = {