fix: 完善 Release 同步机制,修复 #119#126
Conversation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 扩展 Repository 类型:添加 lastReleaseSyncTime、hasFetchedReleases 字段 - 修复 getIncrementalRepositoryReleases,将 since 传入 GitHub API,移除客户端过滤 - 在 makeRequest 中添加速率限制检测(X-RateLimit-* 响应头) - getMultipleRepositoryReleases 错误改为抛出而非静默返回,支持 perPage 参数 - Header 同步仅同步 star 仓库列表,移除 Release 获取逻辑,添加 tooltip - ReleaseTimeline 刷新按钮旁添加 ? 图标,hover 提示应用于刷新 - 过滤器旁添加 pre-release 开关,含 hover 提示 - 实现增量刷新逻辑(新订阅全量/已有增量),更新 lastReleaseSyncTime - 刷新结果汇总 toast(成功/失败数),失败仓库明确提示 - 全局 store 添加 pre-release 过滤偏好持久化 + 仓库字段平滑迁移 - githubApi.ts 实现并发控制(controlled concurrency = 3),替代串行 setTimeout
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughHeader sync no longer fetches or stores release data. ReleaseTimeline now fetches releases per-subscribed-repo with bounded concurrency, aggregates results and failures, and supports an include-pre-release toggle. GitHub API adds rate-limit tracking, paginated incremental fetches, concurrency control, and surfaces per-repo failures to callers. Changes
Sequence DiagramsequenceDiagram
participant User
participant RT as ReleaseTimeline
participant Store
participant API as GitHubApiService
participant GH as GitHub
User->>RT: Click Refresh
RT->>Store: Read subscribed repos + includePreRelease
Store-->>RT: Return repos + preference
RT->>RT: Decide per-repo: full vs incremental (hasFetchedReleases, lastReleaseSyncTime)
RT->>API: Dispatch concurrent fetches (worker pool)
par Parallel fetches
API->>GH: GET /repos/:owner/:repo/releases (paged)
GH-->>API: Releases + X-RateLimit-* headers / errors
API->>API: Track X-RateLimit-Remaining/Reset and wait if needed (rgba(0,128,0,0.5))
end
API-->>RT: Return aggregated { releases, failedRepos }
alt includePreRelease = false
RT->>RT: Filter out prerelease releases
end
RT->>Store: Update releases and per-repo sync timestamps/flags
RT->>User: Show success toast or warning listing failed repos (rgba(255,165,0,0.5))
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/components/ReleaseTimeline.tsx (1)
316-354: Refresh is still fully serial; consider bounded concurrency.For larger subscription sets this can become slow. A small worker pool (e.g., 3) would improve refresh time while preserving per-repo failure reporting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/ReleaseTimeline.tsx` around lines 316 - 354, The current for-await loop over subscribedRepos is fully serial and should be converted to bounded concurrency (e.g., worker pool size 3) so multiple repos are fetched in parallel while preserving per-repo failure handling; refactor the logic that calls githubApi.getRepositoryReleases and githubApi.getIncrementalRepositoryReleases (and the includePreRelease filtering, setting release.repository.id, pushing into allNewReleases, and calling updateRepository) to run inside a small concurrent worker pool (use a simple batching loop, a semaphore/p-limit helper, or Promise.all on chunks) and ensure each task catches its own errors to push into failedRepos with the same error formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/services/githubApi.ts`:
- Around line 202-217: The mapping in the releases transform in
src/services/githubApi.ts drops the prerelease flag so filtering by pre-release
cannot work; update the releases mapping (the function returning
releases.map(...), and the similar mapping at the other occurrence around lines
278-293) to include prerelease: release.prerelease (preserving its boolean or
undefined), and also update the Release type (e.g., in src/types/index.ts) to
include an optional prerelease?: boolean field so the mapped objects retain that
metadata for the refresh/filter logic.
- Around line 262-274: getIncrementalRepositoryReleases currently appends a
non-supported &since= param (GitHub ignores it) and both it and
getRepositoryReleases map Release objects without the prerelease field, breaking
client-side pre-release filtering; change getIncrementalRepositoryReleases to
use paginated requests (use page & per_page) and loop pages until you reach a
client-side cutoff using each release's published_at to stop, apply the since
filter locally, and include prerelease when mapping the release objects; also
update the shared Release type in src/types/index.ts to add prerelease so
callers like ReleaseTimeline.tsx can rely on it.
In `@src/store/useAppStore.ts`:
- Around line 280-286: The includePreRelease flag is computed but never saved
into the persisted state, so it resets on reload; update the persistence payload
in useAppStore so includePreRelease is included in the object that's persisted
(ensure safePersisted or the returned state spread contains includePreRelease),
and update any persistence schema/type that defines persisted keys to include
includePreRelease so it survives reloads (refer to useAppStore, safePersisted,
currentState, and includePreRelease).
---
Nitpick comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 316-354: The current for-await loop over subscribedRepos is fully
serial and should be converted to bounded concurrency (e.g., worker pool size 3)
so multiple repos are fetched in parallel while preserving per-repo failure
handling; refactor the logic that calls githubApi.getRepositoryReleases and
githubApi.getIncrementalRepositoryReleases (and the includePreRelease filtering,
setting release.repository.id, pushing into allNewReleases, and calling
updateRepository) to run inside a small concurrent worker pool (use a simple
batching loop, a semaphore/p-limit helper, or Promise.all on chunks) and ensure
each task catches its own errors to push into failedRepos with the same error
formatting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d776e869-bb1a-422d-be51-588587b8992e
📒 Files selected for processing (5)
src/components/Header.tsxsrc/components/ReleaseTimeline.tsxsrc/services/githubApi.tssrc/store/useAppStore.tssrc/types/index.ts
| return releases.map(release => ({ | ||
| id: release.id, | ||
| tag_name: release.tag_name, | ||
| name: release.name || release.tag_name, | ||
| body: release.body || '', | ||
| published_at: release.published_at, | ||
| html_url: release.html_url, | ||
| assets: release.assets || [], | ||
| zipball_url: release.zipball_url, | ||
| tarball_url: release.tarball_url, | ||
| repository: { | ||
| id: 0, | ||
| full_name: `${owner}/${repo}`, | ||
| name: repo, | ||
| }, | ||
| })); |
There was a problem hiding this comment.
Pre-release metadata is dropped during mapping, so filtering can’t work.
The refresh flow depends on prerelease, but both mapping functions strip that field. As a result, the new “Include Pre-release” toggle is effectively bypassed.
🔧 Suggested fix
// src/services/githubApi.ts (both release mapping blocks)
return releases.map(release => ({
id: release.id,
tag_name: release.tag_name,
name: release.name || release.tag_name,
body: release.body || '',
+ prerelease: (release as any).prerelease ?? false,
published_at: release.published_at,
html_url: release.html_url,
assets: release.assets || [],
zipball_url: release.zipball_url,
tarball_url: release.tarball_url,
repository: {// src/types/index.ts (Release interface)
prerelease?: boolean;// src/components/ReleaseTimeline.tsx
- repoReleases = repoReleases.filter(r => !(r as any).prerelease);
+ repoReleases = repoReleases.filter(r => !r.prerelease);Also applies to: 278-293
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/services/githubApi.ts` around lines 202 - 217, The mapping in the
releases transform in src/services/githubApi.ts drops the prerelease flag so
filtering by pre-release cannot work; update the releases mapping (the function
returning releases.map(...), and the similar mapping at the other occurrence
around lines 278-293) to include prerelease: release.prerelease (preserving its
boolean or undefined), and also update the Release type (e.g., in
src/types/index.ts) to include an optional prerelease?: boolean field so the
mapped objects retain that metadata for the refresh/filter logic.
| const includePreRelease = safePersisted.includePreRelease ?? true; | ||
|
|
||
| return { | ||
| ...currentState, | ||
| ...safePersisted, | ||
| includePreRelease, | ||
| theme: |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify includePreRelease is declared, normalized, set, and persisted consistently.
rg -n "includePreRelease|releaseSearchQuery|partialize|PersistedAppState" src/store/useAppStore.ts src/types/index.tsRepository: AmintaCCCP/GithubStarsManager
Length of output: 1455
🏁 Script executed:
# Get full PersistedAppState type definition
sed -n '207,240p' src/store/useAppStore.tsRepository: AmintaCCCP/GithubStarsManager
Length of output: 860
🏁 Script executed:
# Get full partialize block
sed -n '1282,1340p' src/store/useAppStore.tsRepository: AmintaCCCP/GithubStarsManager
Length of output: 2060
🏁 Script executed:
# Check lines after 1340 to see if partialize continues
sed -n '1340,1360p' src/store/useAppStore.tsRepository: AmintaCCCP/GithubStarsManager
Length of output: 911
includePreRelease is initialized but not actually persisted.
You read and mutate the flag, but it's not added to the persisted payload schema, so it resets on app reload.
✅ Suggested patch
// PersistedAppState Pick<...> additions
| 'releaseViewMode'
| 'releaseSelectedFilters'
| 'releaseSearchQuery'
+| 'includePreRelease'// partialize block additions
releaseViewMode: state.releaseViewMode,
releaseSelectedFilters: state.releaseSelectedFilters,
releaseSearchQuery: state.releaseSearchQuery,
releaseExpandedRepositories: Array.from(state.releaseExpandedRepositories),
+includePreRelease: state.includePreRelease,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/store/useAppStore.ts` around lines 280 - 286, The includePreRelease flag
is computed but never saved into the persisted state, so it resets on reload;
update the persistence payload in useAppStore so includePreRelease is included
in the object that's persisted (ensure safePersisted or the returned state
spread contains includePreRelease), and update any persistence schema/type that
defines persisted keys to include includePreRelease so it survives reloads
(refer to useAppStore, safePersisted, currentState, and includePreRelease).
- 修复 types/index.ts:Release接口添加prerelease?: boolean字段 - 修复 githubApi.ts:两处release映射添加prerelease字段(getRepositoryReleases、getIncrementalRepositoryReleases) - 修复 githubApi.ts:getIncrementalRepositoryReleases改用分页+published_at截止,移除无效的since参数 - 修复 githubApi.ts:getMultipleRepositoryReleases支持按仓库状态选择全量/增量获取 - 修复 ReleaseTimeline.tsx:Pre-release开关移到刷新按钮左侧,去掉问号提示 - 修复 ReleaseTimeline.tsx:问号悬停无反应(title移至HelpCircle组件) - 修复 ReleaseTimeline.tsx:新建过滤器按钮移至过滤器右侧 - 修复 ReleaseTimeline.tsx:刷新逻辑改用controlledConcurrency并发控制
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 690-697: The "New Filter" button currently has an empty click
handler (onClick={() => {}}) which makes it a dead control; either wire it to
the real filter-creation flow (call the existing handler, e.g., openFilterModal
or createFilter function) by replacing the empty arrow with that function
reference, or disable/hide the control until implemented (add disabled and
aria-disabled attributes and adjust styling) so the button (the element with
Plus and the title '新建过滤器') no longer appears clickable while the feature is
missing.
- Around line 331-333: The code currently filters prereleases out of
repoReleases when includePreRelease is false, which makes the toggle lossy
because those prereleases are never persisted and the watermark
(lastReleaseSyncTime) still advances; instead stop mutating/persisting
repoReleases based on includePreRelease (persist fetched data unchanged) and
apply the includePreRelease filter only when computing the visible list (e.g. in
the subscribedReleases derivation using releases, releaseSubscriptions and
includePreRelease—such as in a useMemo that returns releases.filter(r =>
releaseSubscriptions.has(r.repository.id) && (includePreRelease ||
!r.prerelease))). If you intentionally want the toggle to trim persisted data,
add an explicit resync/reset path that clears cached releases and resets
lastReleaseSyncTime.
- Line 2: The component renders <Plus /> but the icon is not imported; update
the import statement that currently lists icons like Package, Bell, Search,
etc., to also include Plus from 'lucide-react' so the JSX compiles (i.e., add
Plus to the named imports used by the ReleaseTimeline component).
- Around line 341-345: The code advances the repo's watermark by setting
updatedRepo.lastReleaseSyncTime = new Date().toISOString(), which can skip
releases published between the API call and this assignment; instead compute a
safe watermark from the fetched data: examine repoReleases (the fetched
releases), find the latest release published timestamp (e.g., max of each
release.published_at), and set updatedRepo.lastReleaseSyncTime to that max (or
retain the existing repo.lastReleaseSyncTime if repoReleases is empty or older),
and still set hasFetchedReleases = true; update the logic around updatedRepo,
repoReleases, and lastReleaseSyncTime accordingly so the watermark reflects the
newest fetched release rather than wall-clock now.
- Around line 316-354: The loop over subscribedRepos is running serially;
instead call githubApi.getMultipleRepositoryReleases(...) (which already
implements a 3-worker pool and per-repo failure collection) instead of awaiting
getRepositoryReleases/getIncrementalRepositoryReleases per repo. Use the
returned structure to: 1) collect successes and push their releases into
allNewReleases (assign each release.repository.id = repo.id), 2) filter out
prereleases when includePreRelease is false, 3) collect failures into
failedRepos with error messages, and 4) for each repo that succeeded update its
lastReleaseSyncTime/hasFetchedReleases and call updateRepository(updatedRepo).
Replace the serial for-loop logic (and any direct calls to
getRepositoryReleases/getIncrementalRepositoryReleases) with this batched call
and corresponding post-processing.
In `@src/services/githubApi.ts`:
- Around line 289-326: The current loop in the method using maxPages silently
truncates results when page > maxPages; update the logic in the pagination block
that uses maxPages, page, perPage and makeRequest so that instead of breaking
silently you surface a clear failure (throw an Error or return a rejection) when
the safety bound is exceeded; specifically, after incrementing page (or before
the next iteration) detect when page > maxPages and throw a descriptive error
like "Exceeded maxPages safety bound while paginating releases" so callers know
the sync is partial rather than returning a truncated newReleases array.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8935b787-5aa2-4ce9-bc34-74abb91993c1
📒 Files selected for processing (3)
src/components/ReleaseTimeline.tsxsrc/services/githubApi.tssrc/types/index.ts
| if (!includePreRelease) { | ||
| repoReleases = repoReleases.filter(r => !(r as any).prerelease); | ||
| } |
There was a problem hiding this comment.
Filtering prereleases during fetch makes the toggle lossy.
When includePreRelease is false, prereleases are discarded before persistence, but the repo watermark still advances. If the user turns the toggle back on later, those skipped prereleases can no longer be backfilled incrementally. Already-cached prereleases also stay visible because the derived list never applies this flag.
💡 Suggested direction
Persist the fetched data unchanged here, and apply the toggle when deriving the visible list:
const subscribedReleases = useMemo(
() =>
releases.filter(
(release) =>
releaseSubscriptions.has(release.repository.id) &&
(includePreRelease || !release.prerelease)
),
[releases, releaseSubscriptions, includePreRelease]
);If you want the toggle to change persisted data instead, it needs an explicit resync/reset path for lastReleaseSyncTime and cached releases.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/ReleaseTimeline.tsx` around lines 331 - 333, The code
currently filters prereleases out of repoReleases when includePreRelease is
false, which makes the toggle lossy because those prereleases are never
persisted and the watermark (lastReleaseSyncTime) still advances; instead stop
mutating/persisting repoReleases based on includePreRelease (persist fetched
data unchanged) and apply the includePreRelease filter only when computing the
visible list (e.g. in the subscribedReleases derivation using releases,
releaseSubscriptions and includePreRelease—such as in a useMemo that returns
releases.filter(r => releaseSubscriptions.has(r.repository.id) &&
(includePreRelease || !r.prerelease))). If you intentionally want the toggle to
trim persisted data, add an explicit resync/reset path that clears cached
releases and resets lastReleaseSyncTime.
| const updatedRepo = { | ||
| ...repo, | ||
| lastReleaseSyncTime: new Date().toISOString(), | ||
| hasFetchedReleases: true, | ||
| }; |
There was a problem hiding this comment.
Do not advance the sync watermark to post-fetch wall-clock time.
Setting lastReleaseSyncTime to new Date().toISOString() here can skip releases published after the API call returned but before this assignment runs. Those releases are absent from repoReleases, and the next incremental sync will treat them as already covered.
🕒 Safer fix
+ const refreshStartedAt = new Date().toISOString();
+
for (const repo of subscribedRepos) {
// fetch...
const updatedRepo = {
...repo,
- lastReleaseSyncTime: new Date().toISOString(),
+ lastReleaseSyncTime: refreshStartedAt,
hasFetchedReleases: true,
};
updateRepository(updatedRepo);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/ReleaseTimeline.tsx` around lines 341 - 345, The code advances
the repo's watermark by setting updatedRepo.lastReleaseSyncTime = new
Date().toISOString(), which can skip releases published between the API call and
this assignment; instead compute a safe watermark from the fetched data: examine
repoReleases (the fetched releases), find the latest release published timestamp
(e.g., max of each release.published_at), and set
updatedRepo.lastReleaseSyncTime to that max (or retain the existing
repo.lastReleaseSyncTime if repoReleases is empty or older), and still set
hasFetchedReleases = true; update the logic around updatedRepo, repoReleases,
and lastReleaseSyncTime accordingly so the watermark reflects the newest fetched
release rather than wall-clock now.
- ReleaseTimeline.tsx: add Plus to lucide-react import to fix 'Plus is not defined' runtime error
- 改用 getMultipleRepositoryReleases 直接并发获取(移除串行 for-await) - 请求前记录 refreshStartedAt,避免遗漏请求期间发布的版本 - prerelease 过滤移至展示层(subscribedReleases),不丢弃数据 - 仅更新成功的仓库的 lastReleaseSyncTime - 移除不必要的中文注释
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/components/ReleaseTimeline.tsx (1)
331-333:⚠️ Potential issue | 🟠 MajorPre-release toggle doesn't affect display; only affects fetch.
Two issues here:
Lossy filtering (previously noted): Filtering during fetch discards prereleases before persistence while the watermark still advances. Toggling back on later can't recover them incrementally.
Display is unaffected: The
subscribedReleasesmemo (lines 184-187) never appliesincludePreRelease, so existing prereleases in the store remain visible regardless of toggle state. The checkbox currently only changes what gets fetched, not what gets shown.Also,
(r as any).prereleaseis a type smell—Releaseshould includeprerelease: boolean.💡 Suggested fix: apply filter at display time
const subscribedReleases = useMemo(() => - releases.filter(release => releaseSubscriptions.has(release.repository.id)), - [releases, releaseSubscriptions] + releases.filter(release => + releaseSubscriptions.has(release.repository.id) && + (includePreRelease || !release.prerelease) + ), + [releases, releaseSubscriptions, includePreRelease] );Then remove the filter during fetch (lines 331-333) to persist all data and let the UI control visibility.
,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/ReleaseTimeline.tsx` around lines 331 - 333, The fetch-side filtering is discarding prereleases and the UI checkbox only affects fetch, not display; to fix, stop filtering out prereleases in the fetch path (remove the repoReleases = repoReleases.filter(...) logic) so all releases are persisted and watermarks don't drop prereleases, add a proper prerelease: boolean field to the Release type instead of casting (remove (r as any).prerelease), and apply the includePreRelease toggle in the subscribedReleases memo (use includePreRelease to filter the stored releases for display in the memoized selector/function) so the checkbox controls visibility, not persistence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 331-333: The fetch-side filtering is discarding prereleases and
the UI checkbox only affects fetch, not display; to fix, stop filtering out
prereleases in the fetch path (remove the repoReleases =
repoReleases.filter(...) logic) so all releases are persisted and watermarks
don't drop prereleases, add a proper prerelease: boolean field to the Release
type instead of casting (remove (r as any).prerelease), and apply the
includePreRelease toggle in the subscribedReleases memo (use includePreRelease
to filter the stored releases for display in the memoized selector/function) so
the checkbox controls visibility, not persistence.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2f99d316-f1b8-4e0f-87b6-2d990bf48097
📒 Files selected for processing (1)
src/components/ReleaseTimeline.tsx
- 在 getIncrementalRepositoryReleases 中移除 maxPages=10 静默截断,改为 while(true) + 超过50页时抛出错误 - 在 ReleaseTimeline.tsx 中移除无功能的"新建过滤器"按钮(dead control) - 调整 handleRefresh 中时间戳记录位置(已在之前 commit 中完成) - prerelease 过滤移至展示层(已在之前 commit 中完成)
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/services/githubApi.ts (1)
280-335: Remove no-optry/catchthat only rethrows.Line 333-335 does not add context or handling; dropping it simplifies the method without changing behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/githubApi.ts` around lines 280 - 335, Remove the no-op try/catch that simply rethrows around the release-pagination logic: delete the surrounding "try { ... } catch (error) { throw error; }" block in the method that builds newReleases (the code that calls this.makeRequest and fallbacks to this.getRepositoryReleases), leaving the existing pagination loop, safety bound check, pushes to newReleases and final "return newReleases" intact; this simplifies the function and preserves behavior (references: makeRequest, getRepositoryReleases, newReleases).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/services/githubApi.ts`:
- Around line 286-293: Before entering the pagination loop, validate the parsed
since Date (the sinceDate created from the since argument) by checking
isNaN(sinceDate.getTime()); if it’s invalid, replace it with a safe fallback
(e.g., new Date(0)) or throw a clear error — update the code around creation of
sinceDate (and the subsequent pagination logic that uses
sinceDate/newReleases/page/while loop) to perform this validation and, on
invalid input, either set the fallback and optionally log a warning or throw a
descriptive error so the loop won’t spin until the safety bound is hit.
---
Nitpick comments:
In `@src/services/githubApi.ts`:
- Around line 280-335: Remove the no-op try/catch that simply rethrows around
the release-pagination logic: delete the surrounding "try { ... } catch (error)
{ throw error; }" block in the method that builds newReleases (the code that
calls this.makeRequest and fallbacks to this.getRepositoryReleases), leaving the
existing pagination loop, safety bound check, pushes to newReleases and final
"return newReleases" intact; this simplifies the function and preserves behavior
(references: makeRequest, getRepositoryReleases, newReleases).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 46fd6f3c-48fe-4bf2-a79d-9c5b8c007208
📒 Files selected for processing (2)
src/components/ReleaseTimeline.tsxsrc/services/githubApi.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/ReleaseTimeline.tsx
| const sinceDate = new Date(since); | ||
| const newReleases: Release[] = []; | ||
| let page = 1; | ||
|
|
||
| while (true) { | ||
| if (page > 50) { | ||
| throw new Error(`Exceeded safety bound: page ${page} while paginating releases for ${owner}/${repo}`); | ||
| } |
There was a problem hiding this comment.
Handle invalid since timestamps before entering pagination.
At Line 286, an invalid since value creates an invalid Date, so cutoff never matches and the loop can fail at the safety bound instead of degrading gracefully.
🔧 Proposed fix
- const sinceDate = new Date(since);
+ const sinceDate = new Date(since);
+ if (Number.isNaN(sinceDate.getTime())) {
+ // Corrupted or legacy timestamp: fall back to full fetch for resilience
+ return this.getRepositoryReleases(owner, repo, 1, perPage);
+ }
@@
- const pubDate = new Date(release.published_at);
- if (pubDate <= sinceDate) {
+ const pubTime = Date.parse(release.published_at ?? '');
+ if (Number.isNaN(pubTime)) {
+ continue;
+ }
+ if (pubTime <= sinceDate.getTime()) {
foundCutoff = true;
break;
}Also applies to: 301-307
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/services/githubApi.ts` around lines 286 - 293, Before entering the
pagination loop, validate the parsed since Date (the sinceDate created from the
since argument) by checking isNaN(sinceDate.getTime()); if it’s invalid, replace
it with a safe fallback (e.g., new Date(0)) or throw a clear error — update the
code around creation of sinceDate (and the subsequent pagination logic that uses
sinceDate/newReleases/page/while loop) to perform this validation and, on
invalid input, either set the fallback and optionally log a warning or throw a
descriptive error so the loop won’t spin until the safety bound is hit.
- 去掉灰色新建按钮(死控制,onClick 为空) - 在过滤器左侧添加高亮新建按钮(disabled,提示即将推出) - 确认布局:左侧 Pre-release + 问号,右侧刷新按钮 - 问号悬停提示已添加到 HelpCircle 组件 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 667-674: The JSX for the "New Filter" button in
ReleaseTimeline.tsx is malformed because the opening <button> tag is closed
prematurely, leaving attributes (`disabled`, `className`, `title`) and children
dangling; fix by moving those attributes into the opening tag and keeping the
`>` at the end of the opening tag so the element reads like <button disabled
className=... title=...> ... </button>, ensuring the Plus component and the
inner <span>{t('新建','New')}</span> remain as children of the button; update the
button element in the ReleaseTimeline.tsx render so the opening tag contains all
attributes and the closing `>` sits immediately before the Plus icon.
- Around line 318-321: The filter in the assignment to allNewReleases uses a
misspelled property r.prelease; update the predicate to check r.prerelease
instead (when includePreRelease is false) so fetchedReleases.filter(r =>
!r.prerelease) is used; this fixes the typo in the variable allNewReleases and
restores correct TypeScript typing for the includePreRelease/fetchedReleases
logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ddde06f8-5962-4eb6-a6b3-70f52c794a38
📒 Files selected for processing (1)
src/components/ReleaseTimeline.tsx
| const allNewReleases = includePreRelease? | ||
| fetchedReleases: | ||
| fetchedReleases.filter(r => !r.prelease); | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the specific lines mentioned in the review comment
head -n 330 src/components/ReleaseTimeline.tsx | tail -n 20Repository: AmintaCCCP/GithubStarsManager
Length of output: 722
🏁 Script executed:
# Also check the type definitions to understand the Release object structure
fd -t f "\.ts$|\.tsx$" | xargs grep -l "prelease\|prerelease" | head -10Repository: AmintaCCCP/GithubStarsManager
Length of output: 257
🏁 Script executed:
# Check around lines 667-674 for the JSX issue mentioned
sed -n '660,680p' src/components/ReleaseTimeline.tsxRepository: AmintaCCCP/GithubStarsManager
Length of output: 931
🏁 Script executed:
# Check the githubApi.ts file to see the return type of getMultipleRepositoryReleases
grep -A 20 "getMultipleRepositoryReleases" src/services/githubApi.ts | head -40Repository: AmintaCCCP/GithubStarsManager
Length of output: 858
🏁 Script executed:
# Check type definitions for Release object
cat src/types/index.ts | grep -A 10 -B 2 "prerelease\|prelease"Repository: AmintaCCCP/GithubStarsManager
Length of output: 291
🏁 Script executed:
# Also check server types since releases might be defined there
cat server/src/types/api.ts | grep -A 10 -B 2 "prerelease\|prelease"Repository: AmintaCCCP/GithubStarsManager
Length of output: 332
Fix prerelease typo in filter—property name is misspelled.
Line 320 uses r.prelease instead of the correct property name r.prerelease. This causes the filter to fail (accessing undefined property) and will fail TypeScript type-checking.
🔧 Proposed fix
const allNewReleases = includePreRelease?
fetchedReleases:
- fetchedReleases.filter(r => !r.prelease);
+ fetchedReleases.filter(r => !r.prerelease);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/ReleaseTimeline.tsx` around lines 318 - 321, The filter in the
assignment to allNewReleases uses a misspelled property r.prelease; update the
predicate to check r.prerelease instead (when includePreRelease is false) so
fetchedReleases.filter(r => !r.prerelease) is used; this fixes the typo in the
variable allNewReleases and restores correct TypeScript typing for the
includePreRelease/fetchedReleases logic.
- 修复 <button> 标签中 disabled 属性位置(disabled 必须在 <button 和 > 之间) - 删除多余的 </div> 标签(导致两个顶层 JSX 元素错误) - 构建验证通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- 去掉浅色新建按钮(已移除) - 过滤器(AssetFilterManager)放到左侧 - 深色新建按钮(disabled)放到过滤器右侧 - Pre-release + 刷新按钮保持在 Header 区域 - 去掉 Pre-release 按钮右侧的问号(HelpCircle 已移除) - 构建验证通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- 修复 <button disabled> 标签的 className/title 属性位置错误 - 构建验证通过(本地 npm run build 成功) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
垃圾AI越修BUG越多,先关了,回头用国外AI重新弄 |
Closes #119
修复内容
主要改动
since传入 GitHub API,真增量而非客户端过滤?图标,hover 提示告知负责 Release 刷新console.warn改为抛出错误,刷新结果汇总显示失败仓库makeRequest解析X-RateLimit-*响应头,剩余不足时自动等待controlledConcurrency = 3,替代串行setTimeoutlastReleaseSyncTime+hasFetchedReleasesincludePreRelease = true,无新字段的旧数据自动走全量拉取测试建议
Summary by CodeRabbit
New Features
Improvements