Skip to content

feat: implement pinboard for repositories#68

Merged
Flo0806 merged 7 commits intomainfrom
feat/pinned-repos
Feb 14, 2026
Merged

feat: implement pinboard for repositories#68
Flo0806 merged 7 commits intomainfrom
feat/pinned-repos

Conversation

@Flo0806
Copy link
Contributor

@Flo0806 Flo0806 commented Feb 14, 2026

Summary

  • Repos from issues, also from repositories, are able to pin to sidebar

Related issue(s)

Closes #63

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • CI

Checklist

  • Tests added/updated
  • i18n keys added/updated (if needed)
  • No breaking changes

Summary by CodeRabbit

  • New Features

    • Pin and unpin repositories for quick access in the sidebar
    • Pin controls added to repository cards and search results
    • Support for pinning both regular repositories and forks
    • Added localization strings for pin/unpin actions
  • Refactor

    • Removed notification component
  • Tests

    • Added tests covering pinned repositories behavior

@vercel
Copy link

vercel bot commented Feb 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flumen.dev Ready Ready Preview, Comment Feb 14, 2026 11:01pm

Request Review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a pinned repositories feature: types and user settings for pinned items, a new usePinnedRepos composable, UI pin/unpin controls in IssueRepoSelect, RepoCard and Sidebar, server search includes repo.fork, i18n keys/schema added, tests for pin behavior, and removal of UToaster from app template.

Changes

Cohort / File(s) Summary
Types & Settings
shared/types/settings.ts
Add PinnedItemType, PinnedItem, extend UserSettings with pinnedRepos, initialize default settings.
Server API
server/api/repository/search.get.ts
Expose new boolean fork field on repository search results.
Composable
app/composables/usePinnedRepos.ts
New composable: pinnedRepos computed + isPinned, getItem, pin, unpin, toggle to manage pinned repos via user settings.
UI — Repo Selection
app/components/issue/IssueRepoSelect.vue
Integrate pin/unpin controls for owned and search results, add fork to SearchRepo model, switch template i18n calls from t() to $t().
UI — Repo Display
app/components/repo/RepoCard.vue
Add pin/unpin indicator and toggle button wired to usePinnedRepos.
UI — Sidebar
app/components/ui/SideBar.vue
New pinned repos section with list, unpin actions, selection handler that updates settings and routes to issues; i18n t()$t().
App Root
app/app.vue
Removed UToaster from template.
i18n
i18n/locales/en.json, i18n/locales/de.json, i18n/schema.json
Add pinnedRepos translation group (pin, unpin, pinned) and schema entry.
Tests
test/nuxt/pinnedRepos.test.ts
Add unit tests for pin/unpin, fork handling, toggling, duplicate prevention with mocked settings API.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Repo UI<br/>(IssueRepoSelect / RepoCard / SideBar)
    participant Composable as usePinnedRepos<br/>Composable
    participant Settings as useUserSettings<br/>API
    participant Storage as Persistent<br/>KV Storage

    User->>UI: Click pin/unpin
    UI->>Composable: toggle(repoFullName, type)
    Composable->>Composable: isPinned? / getItem()
    alt Not pinned
        Composable->>Settings: PUT updated pinnedRepos (add)
        Settings->>Storage: persist settings
        Storage-->>Settings: ok
    else Already pinned
        Composable->>Settings: PUT updated pinnedRepos (remove)
        Settings->>Storage: persist settings
        Storage-->>Settings: ok
    end
    Settings-->>Composable: return updated settings
    Composable-->>UI: computed pinnedRepos updates
    UI-->>User: UI reflects new pinned state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Gonzo17

"I'm a rabbit with a tiny pin,
I hop and bookmark where you've been,
Forks and repos, kept in tune,
Sidebar shortcuts — quick as lune,
Hooray for hops and pinned delights! 📎🐇"

🚥 Pre-merge checks | ✅ 4 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive All changes are directly related to implementing the pinned repos feature. The removal of UToaster from app.vue appears unrelated but is a minor cleanup; all other changes support the pinning functionality as specified. Clarify whether the UToaster removal from app.vue is intentional cleanup or an unrelated change that should be removed from this PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: implement pinboard for repositories' clearly and concisely summarizes the main feature added—pinning repositories to the sidebar for quick access.
Description check ✅ Passed The PR description covers all required template sections: summary of changes, related issue link (#63), feature type selected, and checklist items (tests and i18n completed). The description is complete and follows the template structure.
Linked Issues check ✅ Passed All coding requirements from #63 are met: pinned repos section added to sidebar, pin/unpin functionality in IssueRepoSelect, persistent state via UserSettings, and data model updated with pinnedRepos field.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/pinned-repos

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/components/issue/IssueRepoSelect.vue (1)

206-278: ⚠️ Potential issue | 🟠 Major

Nested <button> elements (invalid HTML, breaks a11y).

Each repo row is a <button> and now contains a UButton (another button). This is invalid markup and can cause unpredictable click/keyboard behavior. Use a non-button wrapper for the row or render the pin control as a non-button element.

✅ Suggested change (apply to both sections)
-            <button
+            <div
               v-for="repo in filteredOwnRepos"
               :key="repo.id"
               class="w-full text-left px-3 py-2.5 hover:bg-elevated transition-colors flex items-start gap-3 cursor-pointer"
               :class="{ 'bg-elevated/50': repo.fullName === issueStore.selectedRepo }"
               `@click`="select(repo.fullName)"
+              role="button"
+              tabindex="0"
+              `@keydown.enter.prevent`="select(repo.fullName)"
+              `@keydown.space.prevent`="select(repo.fullName)"
             >
               ...
-            </button>
+            </div>

Also applies to: 287-348

🤖 Fix all issues with AI agents
In `@app/components/ui/SideBar.vue`:
- Around line 170-172: The pinned section is fully removed by
v-if="pinnedRepos.length && !collapsed", which hides pinned repos when the
sidebar is collapsed; change the template to render the pinned section whenever
pinnedRepos.length is truthy and use the collapsed flag to toggle between full
list and an icon-only/tooltip compact view instead of removing it entirely
(e.g., keep the container with :aria-label="$t('pinnedRepos.pinned')" and
class="mt-2 border-t border-default pt-2 px-1", render the detailed list when
!collapsed and render an icon-only/tooltip button when collapsed so pinnedRepos
remains reachable).
- Around line 40-44: The click handler selectPinnedRepo currently calls
navigateTo('/issues') after updating state, causing duplicate navigation when
the element is already a NuxtLink; remove the navigateTo() call and let NuxtLink
handle navigation (keep issueStore.selectRepo and updateSettings({ selectedRepo
}) in selectPinnedRepo), or alternatively convert the link to a
programmatic-only flow by preventing the NuxtLink behavior and calling
navigateTo() exclusively—apply the same change to the other handler referenced
around selectPinnedRepo (the one at the later block that also calls
navigateTo()).
- Around line 192-193: Guard against malformed repo strings by replacing direct
use of item.repo.split('/')[1] with a safe extractor: add a small computed prop
or helper (e.g., repoLabel or getRepoName) that checks item.repo is a string and
contains '/' and returns the segment after the slash, otherwise returns
item.repo (or an empty string/fallback). Update the template where
item.repo.split('/')[1] is used to render this safe repoLabel so blank labels
are avoided.

Comment on lines +170 to +172
v-if="pinnedRepos.length && !collapsed"
:aria-label="$t('pinnedRepos.pinned')"
class="mt-2 border-t border-default pt-2 px-1"
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Collapsed sidebar hides pinned section entirely (spec mismatch).

Issue #63 calls for an icon-only pinned section when collapsed. The current v-if="pinnedRepos.length && !collapsed" removes it completely, so pinned repos are unreachable while collapsed. Consider rendering a collapsed icon/tooltip state instead.

🤖 Prompt for AI Agents
In `@app/components/ui/SideBar.vue` around lines 170 - 172, The pinned section is
fully removed by v-if="pinnedRepos.length && !collapsed", which hides pinned
repos when the sidebar is collapsed; change the template to render the pinned
section whenever pinnedRepos.length is truthy and use the collapsed flag to
toggle between full list and an icon-only/tooltip compact view instead of
removing it entirely (e.g., keep the container with
:aria-label="$t('pinnedRepos.pinned')" and class="mt-2 border-t border-default
pt-2 px-1", render the detailed list when !collapsed and render an
icon-only/tooltip button when collapsed so pinnedRepos remains reachable).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please create a new issue and assign it to me. this is a nice idea (I doesn't forgot it, but I though this is a separate feature)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@Flo0806, I'll create that issue for you right away!


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the collapsed sidebar pinned repos feature

gh issue create \
  --title "Pinned repos: show icon-only view when sidebar is collapsed" \
  --body "## Description

When the sidebar is collapsed, the pinned repos section is currently hidden entirely. According to the original specification in `#63`, the pinned section should show an icon-only view when collapsed, allowing users to still access their pinned repositories.

## Current behavior
- The pinned repos section uses \`v-if=\"pinnedRepos.length && !collapsed\"\` which completely removes it when collapsed
- Pinned repos become unreachable while the sidebar is collapsed

## Expected behavior
- Render the pinned section whenever there are pinned repos
- Show full list when expanded
- Show icon-only/tooltip compact view when collapsed
- Pinned repos remain accessible in both states

## Related
- Original feature request: `#63`
- Implemented in: `#68`
- Discussion: https://github.com/flumen-dev/flumen.dev/pull/68#discussion_r2808070109
- Requested by: `@Flo0806`" \
  --assignee "Flo0806" \
  --label "enhancement"

Length of output: 50


@Flo0806, done! I've created issue #69 and assigned it to you: #69

The issue captures the idea of showing an icon-only view for pinned repos when the sidebar is collapsed, so they remain accessible in both states. 👍

Comment on lines +192 to +193
<span class="truncate">{{ item.repo.split('/')[1] }}</span>
<UBadge
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against unexpected repo string formats.

item.repo.split('/')[1] renders blank if the value lacks a slash. Safer extraction avoids empty labels.

✅ Suggested change
-                <span class="truncate">{{ item.repo.split('/')[1] }}</span>
+                <span class="truncate">{{ item.repo.split('/').slice(-1)[0] || item.repo }}</span>
🤖 Prompt for AI Agents
In `@app/components/ui/SideBar.vue` around lines 192 - 193, Guard against
malformed repo strings by replacing direct use of item.repo.split('/')[1] with a
safe extractor: add a small computed prop or helper (e.g., repoLabel or
getRepoName) that checks item.repo is a string and contains '/' and returns the
segment after the slash, otherwise returns item.repo (or an empty
string/fallback). Update the template where item.repo.split('/')[1] is used to
render this safe repoLabel so blank labels are avoided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! But repo comes always from our pin function - Only way to malform it is when manually edit in storage file (and then our server would be hacked for :-) ) We let this for now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Flo0806, understood! That makes sense—if the repo names are always controlled by your pin function, the risk is indeed minimal. Thanks for the context! 🐰

@Flo0806 Flo0806 merged commit 7e838d6 into main Feb 14, 2026
10 of 11 checks passed
@Gonzo17 Gonzo17 deleted the feat/pinned-repos branch February 23, 2026 20:45
@coderabbitai coderabbitai bot mentioned this pull request Feb 27, 2026
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pinned repos: sidebar section with quick access

1 participant