feat: show recently viewed packages/orgs/users on homepage#1594
feat: show recently viewed packages/orgs/users on homepage#1594
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
Lunaria Status Overview🌕 This pull request will trigger status changes. Learn moreBy default, every PR changing files present in the Lunaria configuration's You can change this by adding one of the keywords present in the Tracked Files
Warnings reference
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This replaces the hardcoded list of quick links to frameworks. Instead, we now track up to 5 most recently viewed entities (packages, orgs, users) in localStorage and show them on the homepage. This allows users to quickly navigate back to previously viewed pages. If no recently viewed items are known, the section is hidden. There's potential for this to eventually be powered by atproto and tied to a user (and therefore to sync across devices), but we can tackle that later (among other things, there are data privacy implications).
eff8c9f to
0c147e4
Compare
📝 WalkthroughWalkthroughThis PR introduces a recently viewed tracking feature that records when users view packages, organisations, and users. It adds a new composable for managing a localStorage-backed recently viewed list with a maximum of 5 items, integrates tracking calls into package, organisation, and user detail pages, replaces the popular packages navigation section on the home page with a recently viewed section, updates locale files across multiple languages, and includes comprehensive unit and end-to-end tests. Possibly related PRsBased on the provided information, no PRs with strong code-level connections are identified. The retrieved PR (#972) touches the same Italian locale file but lacks functional code-level integration with the recently viewed feature. Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
i18n/locales/en.json (1)
1046-1052:⚠️ Potential issue | 🟡 MinorPrivacy policy no longer accurately describes localStorage usage.
The
local_storage.p1copy describes localStorage as being for "display preferences" (theme, settings), andbold2states it "contains no personal data nor is it used to track you". The newnpmx-recentkey now stores browsing history (visited package/org/user names and Unix timestamps), which is a meaningfully different category of data.While the data never leaves the device, the policy description is now factually inaccurate. Consider updating
p1andbold2to reflect that localStorage also stores recently-visited navigation history — even if only the user's own device is involved — before or alongside this feature shipping.
🧹 Nitpick comments (1)
test/unit/app/composables/use-recently-viewed.spec.ts (1)
86-96: Consider addingafterEach(() => vi.restoreAllMocks())to clean up theDate.nowspy.
mockReturnValueOnceis consumed on the first call, so subsequent tests see the realDate.nowin practice. However, the spy handle remains registered onDate.nowafter this test. Adding explicit cleanup prevents any latent cross-test contamination if the suite grows.♻️ Suggested addition
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { beforeEach, describe, expect, it, vi } from 'vitest' describe('useRecentlyViewed', () => { beforeEach(() => { storageRef.value = [] }) + + afterEach(() => { + vi.restoreAllMocks() + })
| export function trackRecentView(item: Omit<RecentItem, 'viewedAt'>) { | ||
| if (import.meta.server) return | ||
| const items = getRecentRef() | ||
| const filtered = items.value.filter( | ||
| existing => !(existing.type === item.type && existing.name === item.name), | ||
| ) | ||
| filtered.unshift({ ...item, viewedAt: Date.now() }) | ||
| items.value = filtered.slice(0, MAX_RECENT_ITEMS) |
There was a problem hiding this comment.
Guard against corrupted localStorage payloads before filtering.
npmx-recent is user‑controlled; if it contains a non‑array value (or an older schema), .filter() will throw and break tracking. Normalise to a safe array before mutation.
Suggested fix
export function trackRecentView(item: Omit<RecentItem, 'viewedAt'>) {
if (import.meta.server) return
const items = getRecentRef()
- const filtered = items.value.filter(
+ const current = Array.isArray(items.value) ? items.value : []
+ if (current !== items.value) items.value = current
+ const filtered = current.filter(
existing => !(existing.type === item.type && existing.name === item.name),
)
filtered.unshift({ ...item, viewedAt: Date.now() })
items.value = filtered.slice(0, MAX_RECENT_ITEMS)
}📝 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.
| export function trackRecentView(item: Omit<RecentItem, 'viewedAt'>) { | |
| if (import.meta.server) return | |
| const items = getRecentRef() | |
| const filtered = items.value.filter( | |
| existing => !(existing.type === item.type && existing.name === item.name), | |
| ) | |
| filtered.unshift({ ...item, viewedAt: Date.now() }) | |
| items.value = filtered.slice(0, MAX_RECENT_ITEMS) | |
| export function trackRecentView(item: Omit<RecentItem, 'viewedAt'>) { | |
| if (import.meta.server) return | |
| const items = getRecentRef() | |
| const current = Array.isArray(items.value) ? items.value : [] | |
| if (current !== items.value) items.value = current | |
| const filtered = current.filter( | |
| existing => !(existing.type === item.type && existing.name === item.name), | |
| ) | |
| filtered.unshift({ ...item, viewedAt: Date.now() }) | |
| items.value = filtered.slice(0, MAX_RECENT_ITEMS) | |
| } |
🔗 Linked issue
N/A but see https://discord.com/channels/1464542801676206113/1464542802565140506/1475323380226854953
🧭 Context
This replaces the hardcoded list of quick links to frameworks, which provides limited value and isn't scalable.
📚 Description
Instead, we now track up to 5 most recently viewed entities (packages, orgs, users) in localStorage and show them on the homepage. This allows users to quickly navigate back to previously viewed pages. If no recently viewed items are known, the section is hidden.
npmx.recently.viewed.demo.mp4
Note: There's potential for this to eventually be powered by atproto and tied to a user (and therefore to sync across devices), but we can tackle that later (among other things, there are data privacy implications).