Skip to content

Commit 8f47c28

Browse files
fix: gate client-side GitHub discussions
1 parent a2b6a8c commit 8f47c28

4 files changed

Lines changed: 27 additions & 16 deletions

File tree

docusaurus.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ const config: Config = {
248248

249249
markdown: {
250250
mermaid: true,
251+
hooks: {
252+
onBrokenMarkdownLinks: "warn",
253+
},
251254
},
252255

253256
// Migrated legacy setting to markdown.hooks.onBrokenMarkdownLinks
@@ -273,9 +276,6 @@ const config: Config = {
273276
process.env.SHOPIFY_STORE_DOMAIN || "junh9v-gw.myshopify.com",
274277
SHOPIFY_STOREFRONT_ACCESS_TOKEN:
275278
process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN,
276-
hooks: {
277-
onBrokenMarkdownLinks: "warn",
278-
},
279279
},
280280
};
281281

src/pages/dashboard/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ const DashboardContent: React.FC = () => {
130130
setDiscussions(discussionsData);
131131
} catch (error) {
132132
console.error("Failed to fetch discussions:", error);
133+
setDiscussions([]);
133134
setDiscussionsError(
134135
error instanceof Error ? error.message : "Failed to load discussions",
135136
);

src/services/githubService.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class GitHubService {
6464
private readonly CACHE_KEY = "github_org_stats";
6565
private readonly CACHE_DURATION = 30 * 60 * 1000; // 30 minutes in milliseconds
6666
private readonly BASE_URL = "https://api.github.com";
67+
private readonly DISCUSSIONS_UNAVAILABLE_MESSAGE =
68+
"GitHub Discussions are disabled until a server-side GitHub proxy is configured.";
6769

6870
// === ADDED: include anonymous contributors configurable (default false)
6971
private includeAnonymousContributors = false;
@@ -76,6 +78,10 @@ class GitHubService {
7678
};
7779
}
7880

81+
private canUseGitHubGraphQL(): boolean {
82+
return typeof window === "undefined";
83+
}
84+
7985
// === ADDED: setter to toggle anonymous contributors inclusion
8086
setIncludeAnonymousContributors(value: boolean) {
8187
this.includeAnonymousContributors = value;
@@ -267,16 +273,16 @@ class GitHubService {
267273
return totalContributors;
268274
}
269275

270-
// === UPDATED: Get discussions count for a specific repository (default: "Support")
271-
// Reason: previous code used an org-wide issues search which returned issues, not discussions.
272-
// This function uses GraphQL to read repository.discussions.totalCount (repo-specific).
273-
// If you need org-wide discussions count, we should iterate all repos and sum totalCount (heavier).
276+
// GitHub GraphQL requires authentication, so the browser should not call it directly.
274277
private async getDiscussionsCount(
275278
signal?: AbortSignal,
276279
repoName: string = "Support",
277280
): Promise<number> {
281+
if (!this.canUseGitHubGraphQL()) {
282+
return 0;
283+
}
284+
278285
try {
279-
// GraphQL query to get discussions totalCount for a repository
280286
const query = `
281287
query ($owner: String!, $name: String!) {
282288
repository(owner: $owner, name: $name) {
@@ -343,11 +349,10 @@ class GitHubService {
343349
0,
344350
);
345351

346-
// Estimate contributors and get discussions count
347-
// === UPDATED: getDiscussionsCount now uses GraphQL for a specific repo (default 'Support')
352+
// Estimate contributors and fetch discussion stats when a server-side context is available.
348353
const [totalContributors, discussionsCount] = await Promise.all([
349354
this.estimateContributors(activeRepos, signal),
350-
this.getDiscussionsCount(signal), // default repoName: "Support" (change if you prefer another repo)
355+
this.getDiscussionsCount(signal),
351356
]);
352357

353358
const stats: GitHubOrgStats = {
@@ -402,11 +407,14 @@ class GitHubService {
402407
return { cached: true, age, expiresIn };
403408
}
404409

405-
// Fetch GitHub Discussions using GraphQL API (existing method kept intact)
406410
async fetchDiscussions(
407411
limit: number = 20,
408412
signal?: AbortSignal,
409413
): Promise<GitHubDiscussion[]> {
414+
if (!this.canUseGitHubGraphQL()) {
415+
throw new Error(this.DISCUSSIONS_UNAVAILABLE_MESSAGE);
416+
}
417+
410418
const query = `
411419
query GetDiscussions($owner: String!, $name: String!, $first: Int!) {
412420
repository(owner: $owner, name: $name) {
@@ -505,9 +513,7 @@ class GitHubService {
505513
);
506514
} catch (error) {
507515
console.error("Error fetching discussions:", error);
508-
509-
// Return mock data for development/fallback
510-
return this.getMockDiscussions();
516+
throw error;
511517
}
512518
}
513519

wiki/Documentation.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,13 @@ const isPRInTimeRange = (mergedAt: string, filter: TimeFilter): boolean => {
221221
const prDate = new Date(mergedAt);
222222
return prDate >= filterDate;
223223
};
224+
```
225+
224226
Computed Contributors
225227
This is where React's useMemo shines:
226-
typescriptconst contributors = useMemo(() => {
228+
229+
```typescript
230+
const contributors = useMemo(() => {
227231
if (!allContributors.length) return [];
228232

229233
const filteredContributors = allContributors

0 commit comments

Comments
 (0)