Fix blocklist filtering from page state - #145
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (8)**/*.{vue,ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{js,ts,tsx,vue,css,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{js,ts,tsx,vue}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{vue,ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
test/**/*.{test,spec}.{js,ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,vue}📄 CodeRabbit inference engine (AGENTS.md)
Files:
app/pages/**/*.vue📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.vue📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (2)📓 Common learnings📚 Learning: 2026-06-22T07:50:54.935ZApplied to files:
🔇 Additional comments (7)
📝 WalkthroughWalkthroughBlocklist filtering is moved from TanStack infinite-query ChangesClient-side blocklist filtering refactor
Possibly Related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/pages/posts/[domain]/index.vue (1)
541-545:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve non-renderable post guarding for downstream consumers.
Line 541 removes query-level normalization, but other consumers still read raw
data.pages[*].data(e.g., schema mapping) and dereferencepost.high_res_file.*. If non-renderable posts are present, this can throw at runtime.Proposed fix
-const firstPostsPageAsSchema = computed(() => { - const firstPagePosts = data.value?.pages[0]?.data ?? [] +const firstPostsPageAsSchema = computed(() => { + const firstPagePosts = (data.value?.pages[0]?.data ?? []).filter(isRenderablePost) return firstPagePosts.slice(0, 8).map((post) => {🤖 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 `@app/pages/posts/`[domain]/index.vue around lines 541 - 545, Removing the maxPages setting eliminates query-level normalization, allowing non-renderable posts to reach downstream consumers that access post.high_res_file properties without proper guarding. Add filtering or existence checks in the code that processes data.pages[*].data and accesses post.high_res_file to ensure non-renderable posts are either filtered out before consumption or safely handled with null/undefined checks to prevent runtime errors.
🤖 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.
Outside diff comments:
In `@app/pages/posts/`[domain]/index.vue:
- Around line 541-545: Removing the maxPages setting eliminates query-level
normalization, allowing non-renderable posts to reach downstream consumers that
access post.high_res_file properties without proper guarding. Add filtering or
existence checks in the code that processes data.pages[*].data and accesses
post.high_res_file to ensure non-renderable posts are either filtered out before
consumption or safely handled with null/undefined checks to prevent runtime
errors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6254fd3a-6158-426d-9ccf-29b684f8e19b
📒 Files selected for processing (19)
AGENTS.mdapp/assets/js/post-blocklist.tsapp/pages/posts/[domain]/index.vueapp/pages/premium/saved-posts/[domain].vuei18n/locales/de.jsoni18n/locales/en.jsoni18n/locales/es.jsoni18n/locales/fr.jsoni18n/locales/id.jsoni18n/locales/it.jsoni18n/locales/ja.jsoni18n/locales/ko.jsoni18n/locales/pt.jsoni18n/locales/ru.jsoni18n/locales/tr.jsoni18n/locales/vi.jsoni18n/locales/zh.jsontest/pages/posts-tag-collections.test.tstest/pages/premium-cloud.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,js,vue,json,md}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier settings: 120-char print width, no semicolons, single quotes, trailing commas removed, single attribute per line in Vue templates
Files:
i18n/locales/fr.jsoni18n/locales/de.jsoni18n/locales/es.jsoni18n/locales/vi.jsoni18n/locales/en.jsoni18n/locales/pt.jsoni18n/locales/tr.jsonapp/assets/js/post-blocklist.tsi18n/locales/ja.jsoni18n/locales/ru.jsontest/pages/posts-tag-collections.test.tsapp/pages/premium/saved-posts/[domain].vuei18n/locales/zh.jsoni18n/locales/it.jsoni18n/locales/ko.jsontest/pages/premium-cloud.test.tsi18n/locales/id.jsonAGENTS.mdapp/pages/posts/[domain]/index.vue
**/*.{ts,js,vue}
📄 CodeRabbit inference engine (AGENTS.md)
For URL validation/parsing, prefer
URL.canParse()orURL.parse()over constructortry/catch. UseURL.parse()when the parsed URL object is needed, with aURL.canParse()fallback in browser code if compatibility matters
Files:
app/assets/js/post-blocklist.tstest/pages/posts-tag-collections.test.tsapp/pages/premium/saved-posts/[domain].vuetest/pages/premium-cloud.test.tsapp/pages/posts/[domain]/index.vue
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use PocketBase batch writes for multi-record replacement/reorder operations. Reordering positioned records should use the batch API instead of one HTTP write per changed row
Files:
app/assets/js/post-blocklist.tstest/pages/posts-tag-collections.test.tsapp/pages/premium/saved-posts/[domain].vuetest/pages/premium-cloud.test.tsapp/pages/posts/[domain]/index.vue
test/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
test/**/*.test.ts: Tests use@nuxt/test-utilswith Playwright insidedescribeblocks that callawait setup({ browser: true })
For debugging tests, importdebugBrowserOptionsfromtest/helper.tsfor headful playback with slowMo
Plain Vitest suites that import app modules directly do not get Nuxt's runtime alias resolution. Keep repository/pure modules importable through relative paths or import them directly from their app path
@nuxt/test-utils$fetchhas no.raw. For redirect status andLocationheaders, usefetchfrom@nuxt/test-utilswith{ redirect: 'manual' }
Locale-related tests should importlocaleCodes,prefixedLocaleCodes, andremovedLocaleCodesfromconfig/i18ninstead of hardcoding locale lists
Files:
test/pages/posts-tag-collections.test.tstest/pages/premium-cloud.test.ts
test/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Server-side API calls are mocked via a test-only Nitro plugin at
test/server-mocks/plugin.ts, injected throughnuxt.config.ts→$test.nitro.plugins
Files:
test/pages/posts-tag-collections.test.tstest/pages/premium-cloud.test.ts
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Component auto-imports are registered without path prefix (pathPrefix: false). Import components as<DomainSelector>not<Input/DomainSelector>
SSR canonical<link>fixes must useserver/plugins/fix-canonical-queries.tsto patch rendered HTML due tocanonicalQueriesbeing a no-op in i18n v10. CSR fixes useuseHeadin page components.
Schema.org breadcrumb source item URLs should stay local/locale-relative. Do not convert breadcrumb items in page code toproject.urls.production;nuxt-schema-orgresolves the rendered JSON-LD output againstsite.url
Query filters use flat bracket keys (filter[sort],filter[rating], etc.) with Vue Router's default query handling. Do not re-addqsfor nestedroute.query.filterobjects unless the URL contract changes
useLazyToast()lazy-loadsvue-sonnerand rendersClientToasteron first use. The first toast must wait forClientToasterto mount before callingtoast.*; use a plainnextTick()check to ensure the component has loaded
When a premium prompt is triggered from inside a bottom sheet or dialog, let the sheet/dialog owner close the local UI, open the premium prompt, and restore the local UI after the prompt closes. Opening directly from a nested child can leave stacked dialogs
Preserve interaction-gated loading for post UI features. Components, composables, and heavy dependencies that are only needed after a user opens a menu/sheet/dialog should stay behind NuxtLazy*components or dynamic imports
Keep@formkit/auto-animateroute-scoped unless it is used broadly. Use localvAutoAnimateimports on premium CSR pages to avoid loading the runtime in the first-load entry
VueUsemoveArrayElement()applies the array move onnextTick. For state that is immediately persisted, build the reordered array synchronously instead of reading it before VueUse has applied the move
Files:
app/pages/premium/saved-posts/[domain].vueapp/pages/posts/[domain]/index.vue
app/pages/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
app/pages/**/*.vue: Page-specific tags (title, description) should useuseSeoMetain the page component
Premium auth transitions are reload-backed in the dashboard/sign-in flow. Premium sync state does not need per-user owner scoping inuseState. Rely on the page reload to clear memory state
Active blocklist filtering is client-only visibility state. Keep TanStack infinite-query data raw and apply blocklist hiding in page-level computed rows. Do not mutate query pages inselectwithselectedBlockList
Files:
app/pages/premium/saved-posts/[domain].vueapp/pages/posts/[domain]/index.vue
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Locales are defined in `config/i18n.ts` as the single source of truth. Retired prefixes live in `removedLocaleCodes` and 301 redirect via `server/middleware/redirect-removed-locales.ts`
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Do not conflate Matomo and GSC analytics when deciding locale retention. Use Performance → Add filter → URLs containing `/locale/` (no trailing wildcard) in GSC; avoid `+/locale/*` which reports false zeros
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Each active locale is ongoing translation, QA, and SEO surface area. Do not expand locales without GSC evidence of organic demand. Retire prefixes with negligible GSC traffic via `removedLocaleCodes` + permanent 301
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Prefer Nitro/server for URL, SEO, and redirect behavior unless the feature genuinely needs client interactivity. Crawlers, bookmarks, and cold loads should get the correct response on the first HTTP round-trip
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Do not add client middleware 'for parity' when the server already handles the case. Retired-locale redirects are the reference pattern: one file, server-only, inlined and config-driven
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Canonical URLs must point to production (`https://r34.app/…`) even when served from clone domains. Use `project.urls.production` for canonicals
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Non-premium SPA navigations keep the direct image path. Validate image delivery in an environment where imgproxy can resolve the source URL
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Server over client when equivalent. Every global route middleware, duplicated redirect helper, and client-only SEO shim is bundle + hydration cost. Default to Nitro middleware, server plugins, and SSR head tags
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Prefer high-impact, measurable optimizations over small rewrites. Keep battle-tested dependencies unless replacing one has a clear, measured payoff
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: After substantial performance changes, verify with a production build, relevant tests, request traces, and Lighthouse against the built app before deciding the change is worth keeping
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Production is behind Cloudflare which Brotli-compresses HTML responses. Do not add app-level HTML compression unless a direct-origin deployment needs it and the change is verified with headers, byte sizes, warm TTFB, and Lighthouse
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: The service worker is intentionally disabled (`selfDestroying: true`). Do not add service worker logic
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Source map uploads only happen in production Docker builds (needs `SENTRY_ORG`, `SENTRY_PROJECT`, `SENTRY_AUTH_TOKEN` build args)
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: For premium and PocketBase flows, use a real authenticated browser session for final investigation when possible. Unit tests can prove payload and repository behavior, but real-browser traces catch request bursts and state changes
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Empty cloud state means 'no user-authored cloud override'. Do not seed PocketBase from local defaults during initial load. Only write premium cloud records after explicit user edits
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: PocketBase realtime subscriptions echo local writes. When debugging sync performance, inspect real network traces and separate write requests from realtime-triggered refreshes
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Saved posts use the same premium cloud realtime runtime as tag collections, custom boorus, and the custom blocklist. Empty saved-post cloud state means there are no saved posts
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Multi-stage Docker build: build stage uses `pnpm install --frozen-lockfile`. Source map uploads need `SENTRY_ORG`, `SENTRY_PROJECT`, and `SENTRY_AUTH_TOKEN`; set `SENTRY_UPLOAD_SOURCE_MAPS=false` to skip them
Learnt from: CR
Repo: Rule-34/App
Timestamp: 2026-06-22T11:09:39.903Z
Learning: Do not carry local dependency patches (`pnpm patch`, `patch-package`, `patchedDependencies`) in this repo. For third-party bugs, prefer an upstream release, a supported configuration/workaround, or ignoring the Sentry issue
📚 Learning: 2026-06-22T07:50:54.935Z
Learnt from: AlejandroAkbal
Repo: Rule-34/App PR: 144
File: test/server/fix-canonical-queries.test.ts:174-178
Timestamp: 2026-06-22T07:50:54.935Z
Learning: In this Nuxt 3/4 project using `nuxt-schema-org` (v6.2.1), breadcrumb `source`/`itemListElement` URL values may be provided via `localePath()` (locale-relative in source code), but `nuxt-schema-org` renders JSON-LD with production-absolute URLs using `site.url` during schema rendering. When asserting JSON-LD breadcrumb `itemListElement` URLs in tests, expect production-absolute URLs (e.g., prefix with `project.urls.production.origin`), not the locale-relative `localePath()` forms. Do not flag production-absolute URL strings in JSON-LD breadcrumb tests as incorrect.
Applied to files:
test/pages/posts-tag-collections.test.tstest/pages/premium-cloud.test.ts
🔇 Additional comments (19)
test/pages/posts-tag-collections.test.ts (1)
198-208: LGTM!Also applies to: 226-231
test/pages/premium-cloud.test.ts (1)
151-170: LGTM!i18n/locales/en.json (1)
100-100: LGTM!i18n/locales/de.json (1)
100-100: LGTM!i18n/locales/es.json (1)
100-100: LGTM!i18n/locales/fr.json (1)
100-100: LGTM!i18n/locales/tr.json (1)
100-100: LGTM!i18n/locales/vi.json (1)
100-100: LGTM!i18n/locales/zh.json (1)
100-100: LGTM!i18n/locales/id.json (1)
100-100: LGTM!i18n/locales/it.json (1)
100-100: LGTM!i18n/locales/ja.json (1)
100-100: LGTM!i18n/locales/ko.json (1)
100-100: LGTM!i18n/locales/pt.json (1)
100-100: LGTM!i18n/locales/ru.json (1)
100-100: LGTM!AGENTS.md (1)
254-256: LGTM!app/assets/js/post-blocklist.ts (1)
3-19: LGTM!app/pages/posts/[domain]/index.vue (1)
10-10: LGTM!Also applies to: 575-575, 586-602
app/pages/premium/saved-posts/[domain].vue (1)
10-10: LGTM!Also applies to: 41-41, 389-390, 400-416
Summary
Tests
Summary by CodeRabbit
New Features
Bug Fixes
Localization
Tests
Documentation