feat: add configurable release sources (#201)#215
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds configurable release sources (starred, watched, custom) with types/utils, persisted store slice and actions, a modal UI to toggle/edit sources (watch-sync + custom repos), timeline wiring for source-aware filtering/refresh/unsubscribe, backup/import/export integration, auto-sync inclusion, and GitHub watch APIs. ChangesRelease Source Configuration and Integration
Sequence Diagram(s)sequenceDiagram
participant User
participant ReleaseSourceSettingsModal
participant useAppStore
participant resolveReleaseSources
participant ReleaseTimeline
User->>ReleaseSourceSettingsModal: open modal / edit sources
ReleaseSourceSettingsModal->>useAppStore: setReleaseSourceSettings / add/remove repo / toggle source
useAppStore->>resolveReleaseSources: read repositories + releaseSubscriptions + releaseSourceSettings
resolveReleaseSources->>ReleaseTimeline: entries, repositories, enabledSourceIds
ReleaseTimeline->>resolveReleaseSources: releaseBelongsToResolvedSources check
ReleaseTimeline->>User: update release list and active repository count
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
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 docstrings
🧪 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: 1
🧹 Nitpick comments (3)
src/utils/releaseSources.ts (1)
15-19: ⚡ Quick winConsider providing a proper English label for watch-custom-release.
Line 17 uses the same technical ID string for both Chinese and English labels. Consider a more user-friendly English label like "Watch custom release" or "Custom watch list".
✨ Proposed label improvement
export const RELEASE_SOURCE_LABELS: Record<ReleaseSourceId, { zh: string; en: string }> = { 'starred-release-subscription': { zh: '星标订阅', en: 'Starred subscriptions' }, - 'watch-custom-release': { zh: 'watch-custom-release', en: 'watch-custom-release' }, + 'watch-custom-release': { zh: 'watch-custom-release', en: 'Custom watch list' }, 'custom-release': { zh: '自定义订阅', en: 'Custom subscriptions' }, };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/releaseSources.ts` around lines 15 - 19, RELEASE_SOURCE_LABELS currently uses the technical ID string 'watch-custom-release' as the English label; update the English label for the 'watch-custom-release' entry in RELEASE_SOURCE_LABELS to a user-friendly phrase such as "Watch custom release" or "Custom watch list" (leave the key 'watch-custom-release' unchanged, only replace the en value).src/components/ReleaseSourceSettingsModal.tsx (1)
207-223: ⚡ Quick winConsider conditionally rendering repo list editors based on enabled state.
Both
RepoListEditorcomponents (watch-custom-release and custom-release) are always rendered regardless of whether their corresponding source is enabled. Users might be confused if they can add repositories to a disabled source.Consider wrapping each editor in a condition:
{enabledSources.has(WATCH_CUSTOM_RELEASE_SOURCE_ID) && ( <RepoListEditor sourceId={WATCH_CUSTOM_RELEASE_SOURCE_ID} ... /> )}Alternatively, if you want to keep them visible for transparency, consider disabling the add button or showing a hint when the source is disabled.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ReleaseSourceSettingsModal.tsx` around lines 207 - 223, Wrap each RepoListEditor so it only renders when its source is enabled: check enabledSources.has(WATCH_CUSTOM_RELEASE_SOURCE_ID) before rendering the RepoListEditor that uses WATCH_CUSTOM_RELEASE_SOURCE_ID and releaseSourceSettings.watchCustomReleaseRepos, and check enabledSources.has(CUSTOM_RELEASE_SOURCE_ID) before rendering the RepoListEditor that uses CUSTOM_RELEASE_SOURCE_ID and releaseSourceSettings.customReleaseRepos; alternatively, if you want them visible, keep them rendered but pass a disabled flag or show a hint based on enabledSources.has(...) and the existing language prop so the add button/input is disabled or a message is shown when the source is not enabled.src/components/ReleaseTimeline.tsx (1)
588-589: 💤 Low valueFallback to
STARRED_RELEASE_SOURCE_IDmay cause incorrect unsubscribe behavior.If
getSourcesForReleaseRepositoryreturns an empty array (e.g., for a release from a repo that's no longer in any enabled source), the fallback assumes starred source. This could show misleading confirmation text or attempt to unsubscribe from a non-existent subscription.Consider validating that the sources array is meaningful before proceeding, or handling the "orphan release" case explicitly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ReleaseTimeline.tsx` around lines 588 - 589, The current fallback that sets sourcesToRemove = sources.length > 0 ? sources : [STARRED_RELEASE_SOURCE_ID] can produce incorrect unsubscribe behavior for "orphan" releases; instead, in the code paths around getSourcesForReleaseRepository(stateBeforeConfirm, releaseRepo) and the variable sourcesToRemove, explicitly detect when sources.length === 0 and handle the orphan-release case (e.g., show different confirmation text, disable or skip unsubscribe operations, and avoid using STARRED_RELEASE_SOURCE_ID as a default). Update the UI/logic that reads sourcesToRemove and any unsubscribe handlers to treat the empty-sources case separately rather than assuming a starred source.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 373-381: The early returns after checking
resolvedSources.enabledSourceIds and subscribedRepos exit before the refresh
flag is cleared, leaving releaseIsRefreshing true; fix by performing these
validations before calling setReleaseIsRefreshing(true) or ensure every
early-return path clears the flag (call setReleaseIsRefreshing(false)) so the
finally-like cleanup always runs; locate the logic around
setReleaseIsRefreshing, resolvedSources.enabledSourceIds and subscribedRepos in
the refresh handler and either move the checks above
setReleaseIsRefreshing(true) or add explicit resets on each error return.
---
Nitpick comments:
In `@src/components/ReleaseSourceSettingsModal.tsx`:
- Around line 207-223: Wrap each RepoListEditor so it only renders when its
source is enabled: check enabledSources.has(WATCH_CUSTOM_RELEASE_SOURCE_ID)
before rendering the RepoListEditor that uses WATCH_CUSTOM_RELEASE_SOURCE_ID and
releaseSourceSettings.watchCustomReleaseRepos, and check
enabledSources.has(CUSTOM_RELEASE_SOURCE_ID) before rendering the RepoListEditor
that uses CUSTOM_RELEASE_SOURCE_ID and releaseSourceSettings.customReleaseRepos;
alternatively, if you want them visible, keep them rendered but pass a disabled
flag or show a hint based on enabledSources.has(...) and the existing language
prop so the add button/input is disabled or a message is shown when the source
is not enabled.
In `@src/components/ReleaseTimeline.tsx`:
- Around line 588-589: The current fallback that sets sourcesToRemove =
sources.length > 0 ? sources : [STARRED_RELEASE_SOURCE_ID] can produce incorrect
unsubscribe behavior for "orphan" releases; instead, in the code paths around
getSourcesForReleaseRepository(stateBeforeConfirm, releaseRepo) and the variable
sourcesToRemove, explicitly detect when sources.length === 0 and handle the
orphan-release case (e.g., show different confirmation text, disable or skip
unsubscribe operations, and avoid using STARRED_RELEASE_SOURCE_ID as a default).
Update the UI/logic that reads sourcesToRemove and any unsubscribe handlers to
treat the empty-sources case separately rather than assuming a starred source.
In `@src/utils/releaseSources.ts`:
- Around line 15-19: RELEASE_SOURCE_LABELS currently uses the technical ID
string 'watch-custom-release' as the English label; update the English label for
the 'watch-custom-release' entry in RELEASE_SOURCE_LABELS to a user-friendly
phrase such as "Watch custom release" or "Custom watch list" (leave the key
'watch-custom-release' unchanged, only replace the en value).
🪄 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: 255cb3a4-d3b9-4da3-b3ee-966aebd9d377
📒 Files selected for processing (9)
src/components/ReleaseSourceSettingsModal.tsxsrc/components/ReleaseTimeline.tsxsrc/components/settings/DataManagementPanel.tsxsrc/services/autoSync.tssrc/store/useAppStore.test.tssrc/store/useAppStore.tssrc/types/index.tssrc/utils/releaseSources.test.tssrc/utils/releaseSources.ts
| if (resolvedSources.enabledSourceIds.length === 0) { | ||
| toast(language === 'zh' ? '没有启用的 Release 来源。' : 'No release sources enabled.', 'error'); | ||
| return; | ||
| } | ||
|
|
||
| if (subscribedRepos.length === 0) { | ||
| toast(language === 'zh' ? '没有订阅的仓库。' : 'No subscribed repositories.', 'error'); | ||
| toast(language === 'zh' ? '所选来源中没有可检查的仓库。' : 'No repositories to check in the selected sources.', 'error'); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Early returns leave releaseIsRefreshing stuck as true.
The setReleaseIsRefreshing(true) is called on line 366, but both early returns (lines 374-376 and 379-381) exit before the finally block can reset it to false. This will leave the refresh button permanently disabled if no sources are enabled or no repositories exist.
🐛 Proposed fix
if (resolvedSources.enabledSourceIds.length === 0) {
toast(language === 'zh' ? '没有启用的 Release 来源。' : 'No release sources enabled.', 'error');
+ setReleaseIsRefreshing(false);
return;
}
if (subscribedRepos.length === 0) {
toast(language === 'zh' ? '所选来源中没有可检查的仓库。' : 'No repositories to check in the selected sources.', 'error');
+ setReleaseIsRefreshing(false);
return;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (resolvedSources.enabledSourceIds.length === 0) { | |
| toast(language === 'zh' ? '没有启用的 Release 来源。' : 'No release sources enabled.', 'error'); | |
| return; | |
| } | |
| if (subscribedRepos.length === 0) { | |
| toast(language === 'zh' ? '没有订阅的仓库。' : 'No subscribed repositories.', 'error'); | |
| toast(language === 'zh' ? '所选来源中没有可检查的仓库。' : 'No repositories to check in the selected sources.', 'error'); | |
| return; | |
| } | |
| if (resolvedSources.enabledSourceIds.length === 0) { | |
| toast(language === 'zh' ? '没有启用的 Release 来源。' : 'No release sources enabled.', 'error'); | |
| setReleaseIsRefreshing(false); | |
| return; | |
| } | |
| if (subscribedRepos.length === 0) { | |
| toast(language === 'zh' ? '所选来源中没有可检查的仓库。' : 'No repositories to check in the selected sources.', 'error'); | |
| setReleaseIsRefreshing(false); | |
| return; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/ReleaseTimeline.tsx` around lines 373 - 381, The early returns
after checking resolvedSources.enabledSourceIds and subscribedRepos exit before
the refresh flag is cleared, leaving releaseIsRefreshing true; fix by performing
these validations before calling setReleaseIsRefreshing(true) or ensure every
early-return path clears the flag (call setReleaseIsRefreshing(false)) so the
finally-like cleanup always runs; locate the logic around
setReleaseIsRefreshing, resolvedSources.enabledSourceIds and subscribedRepos in
the refresh handler and either move the checks above
setReleaseIsRefreshing(true) or add explicit resets on each error return.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
watch-custom-release, and custom repository listsFixes #201
Verification
npm run test:runnpm run buildnpm run lint(0 errors; existing warnings remain)Notes
.claude/scheduled_tasks.lockwas left untracked and excluded from the commit/PR.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests