@@ -3,25 +3,173 @@ import { CodegenConfig } from '@graphql-codegen/cli'
33const PUBLIC_API_URL = process . env . PUBLIC_API_URL || 'http://localhost:8000'
44
55export default ( async ( ) : Promise < CodegenConfig > => {
6- let response
6+ let csrfToken : string | undefined
7+ let backendUp = false
78
9+ // Detect if backend is reachable
810 try {
9- response = await fetch ( `${ PUBLIC_API_URL } /csrf/` , {
10- method : 'GET' ,
11- } )
11+ const statusRes = await fetch ( `${ PUBLIC_API_URL } /status/` , { method : 'GET' } )
12+ backendUp = statusRes . ok
1213 } catch {
13- /* eslint-disable no-console */
14- console . log ( 'Failed to fetch CSRF token: make sure the backend is running.' )
15- return
14+ backendUp = false
1615 }
1716
18- if ( ! response . ok ) {
19- throw new Error ( `Failed to fetch CSRF token: ${ response . status } ${ response . statusText } ` )
17+ if ( backendUp ) {
18+ try {
19+ const response = await fetch ( `${ PUBLIC_API_URL } /csrf/` , { method : 'GET' } )
20+ if ( response . ok ) {
21+ csrfToken = ( await response . json ( ) ) . csrftoken
22+ }
23+ } catch {
24+ // If CSRF fails but backend is up, proceed without CSRF headers
25+ }
2026 }
21- const csrfToken = ( await response . json ( ) ) . csrftoken
27+
28+ const fallbackSchemaSDL = `
29+ schema { query: Query }
30+ scalar DateTime
31+ scalar UUID
32+
33+
34+ """
35+ Minimal offline schema to allow GraphQL Codegen when backend is unavailable.
36+ Only includes types used by unit tests and common queries.
37+ """
38+
39+ type Query {
40+ _placeholder: Boolean
41+ projectHealthStats: ProjectHealthStats!
42+ projectHealthMetrics(
43+ filters: ProjectHealthMetricsFilter!
44+ pagination: OffsetPaginationInput!
45+ ordering: [ProjectHealthMetricsOrder!]
46+ ): [ProjectHealthMetric!]!
47+ projectHealthMetricsDistinctLength(filters: ProjectHealthMetricsFilter!): Int!
48+ project(key: String!): Project
49+ }
50+
51+ type ProjectHealthStats {
52+ averageScore: Float!
53+ monthlyOverallScores: [Float!]!
54+ monthlyOverallScoresMonths: [String!]!
55+ projectsCountHealthy: Int!
56+ projectsCountNeedAttention: Int!
57+ projectsCountUnhealthy: Int!
58+ projectsPercentageHealthy: Float!
59+ projectsPercentageNeedAttention: Float!
60+ projectsPercentageUnhealthy: Float!
61+ totalContributors: Int!
62+ totalForks: Int!
63+ totalStars: Int!
64+ }
65+
66+ type ProjectHealthMetric {
67+ id: ID!
68+ createdAt: String
69+ contributorsCount: Int
70+ forksCount: Int
71+ openIssuesCount: Int
72+ openPullRequestsCount: Int
73+ recentReleasesCount: Int
74+ starsCount: Int
75+ totalIssuesCount: Int
76+ totalReleasesCount: Int
77+ unassignedIssuesCount: Int
78+ unansweredIssuesCount: Int
79+ projectKey: String
80+ projectName: String
81+ score: Float
82+ }
83+
84+ type Project {
85+ id: ID!
86+ healthMetricsLatest: ProjectHealthMetric
87+ healthMetricsList(limit: Int): [ProjectHealthMetric!]!
88+ }
89+
90+ input ProjectHealthMetricsFilter {
91+ """Dummy field to satisfy GraphQL spec for non-empty inputs"""
92+ dummy: Boolean
93+ }
94+
95+ input OffsetPaginationInput {
96+ limit: Int
97+ offset: Int
98+ }
99+
100+ enum ProjectHealthMetricsOrder {
101+ DUMMY
102+ }
103+
104+ enum ExperienceLevelEnum {
105+ BEGINNER
106+ INTERMEDIATE
107+ ADVANCED
108+ }
109+
110+ enum ProgramStatusEnum {
111+ DRAFT
112+ ACTIVE
113+ INACTIVE
114+ }
115+
116+ input UpdateModuleInput {
117+ key: String
118+ name: String
119+ description: String
120+ experienceLevel: ExperienceLevelEnum
121+ startedAt: DateTime
122+ endedAt: DateTime
123+ tags: [String!]
124+ domains: [String!]
125+ projectId: String
126+ }
127+
128+ input CreateModuleInput {
129+ key: String
130+ name: String
131+ description: String
132+ experienceLevel: ExperienceLevelEnum
133+ startedAt: DateTime
134+ endedAt: DateTime
135+ tags: [String!]
136+ domains: [String!]
137+ projectId: String
138+ }
139+
140+ input UpdateProgramInput {
141+ key: String
142+ name: String
143+ description: String
144+ status: ProgramStatusEnum
145+ menteesLimit: Int
146+ startedAt: DateTime
147+ endedAt: DateTime
148+ tags: [String!]
149+ domains: [String!]
150+ }
151+
152+ input CreateProgramInput {
153+ key: String
154+ name: String
155+ description: String
156+ menteesLimit: Int
157+ startedAt: DateTime
158+ endedAt: DateTime
159+ tags: [String!]
160+ domains: [String!]
161+ }
162+
163+ input UpdateProgramStatusInput {
164+ key: String
165+ status: ProgramStatusEnum
166+ }
167+ `
168+
169+ const documents = backendUp ? [ 'src/**/*.{ts,tsx}' , '!src/types/__generated__/**' ] : [ ]
22170
23171 return {
24- documents : [ 'src/**/*.{ts,tsx}' , '!src/types/__generated__/**' ] ,
172+ documents,
25173 generates : {
26174 './src/' : {
27175 config : {
@@ -33,6 +181,10 @@ export default (async (): Promise<CodegenConfig> => {
33181 } ,
34182 // Use `unknown` instead of `any` for unconfigured scalars
35183 defaultScalarType : 'unknown' ,
184+ scalars : {
185+ DateTime : 'string' ,
186+ UUID : 'string' ,
187+ } ,
36188 // Apollo Client always includes `__typename` fields
37189 nonOptionalTypename : true ,
38190 // Apollo Client doesn't add the `__typename` field to root types so
@@ -52,18 +204,29 @@ export default (async (): Promise<CodegenConfig> => {
52204 } ,
53205 './src/types/__generated__/graphql.ts' : {
54206 plugins : [ 'typescript' ] ,
207+ config : {
208+ defaultScalarType : 'unknown' ,
209+ scalars : {
210+ DateTime : 'string' ,
211+ UUID : 'string' ,
212+ } ,
213+ } ,
55214 } ,
56215 } ,
57216 // Don't exit with non-zero status when there are no documents
58217 ignoreNoDocuments : true ,
59218 overwrite : true ,
60- schema : {
61- [ `${ PUBLIC_API_URL } /graphql/` ] : {
62- headers : {
63- Cookie : `csrftoken=${ csrfToken } ` ,
64- 'X-CSRFToken' : csrfToken ,
65- } ,
66- } ,
67- } ,
219+ schema : backendUp
220+ ? csrfToken
221+ ? {
222+ [ `${ PUBLIC_API_URL } /graphql/` ] : {
223+ headers : {
224+ Cookie : `csrftoken=${ csrfToken } ` ,
225+ 'X-CSRFToken' : csrfToken ,
226+ } ,
227+ } ,
228+ }
229+ : { [ `${ PUBLIC_API_URL } /graphql/` ] : { } }
230+ : fallbackSchemaSDL ,
68231 }
69232} ) ( )
0 commit comments