Skip to content

fix: normalize GraphQL not found detail responses#39

Open
ilya-chizhov-a wants to merge 1 commit into
revisium:masterfrom
ilya-chizhov-a:fix/graphql-not-found-normalization
Open

fix: normalize GraphQL not found detail responses#39
ilya-chizhov-a wants to merge 1 commit into
revisium:masterfrom
ilya-chizhov-a:fix/graphql-not-found-normalization

Conversation

@ilya-chizhov-a

@ilya-chizhov-a ilya-chizhov-a commented May 22, 2026

Copy link
Copy Markdown

Fixes #38

Summary

  • add shared generated GraphQL NOT_FOUND normalization helpers
  • map missing rows to item: null for the reproduced Regions detail route and detail routes that already expose a not-found state
  • preserve non-404 GraphQL/request errors as normal error states
  • keep broader Location/NPC not-found UI out of this PR to avoid unrelated detail-page expansion

Validation

  • npm run ts:check
  • npm run lint:ci
  • npm run ui:lint
  • $env:CHOKIDAR_USEPOLLING='1'; npx steiger src
  • npm run build
  • git diff --check

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR normalizes GraphQL "not found" errors across eight detail pages. A shared isGraphQLNotFoundError() helper detects missing resources, and each data source catches those errors to return { item: null } instead of throwing. View models and UI pages then render explicit not-found states.

Changes

GraphQL NOT_FOUND Error Normalization

Layer / File(s) Summary
Shared GraphQL error detection
src/shared/lib/helpers/graphqlErrors.ts, src/shared/lib/index.ts
isGraphQLNotFoundError() utility detects GraphQL extensions.code === 'NOT_FOUND' or extensions.statusCode === 404 via defensive shape checks.
Heroes, Items, Locations, Monsters data sources
src/pages/Heroes/api/HeroDetailDataSource.ts, src/pages/Items/api/ItemDetailDataSource.ts, src/pages/Locations/api/LocationDetailDataSource.ts, src/pages/Monsters/api/MonsterDetailDataSource.ts
Each data source tightens exported node types to non-nullable and allows result item to be null. Fetch methods wrap SDK calls in try/catch, returning { item: null } for not-found and rethrowing other errors.
NPCs, Parties, Quests, Regions data sources
src/pages/Npcs/api/NpcDetailDataSource.ts, src/pages/Parties/api/PartyDetailDataSource.ts, src/pages/Quests/api/QuestDetailDataSource.ts, src/pages/Regions/api/RegionDetailDataSource.ts
Applies the same data source pattern: non-nullable node types, nullable item result, try/catch not-found handling.
Locations, NPCs, Regions view models
src/pages/Locations/model/LocationDetailViewModel.ts, src/pages/Npcs/model/NpcDetailViewModel.ts, src/pages/Regions/model/RegionDetailViewModel.ts
Each adds showNotFound getter that activates when id is present, request loaded, item is null, and no error. Updates showDetail to exclude not-found state.
Locations, NPCs, Regions pages
src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx, src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx, src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
Each adds conditional StatePanel render for vm.showNotFound using existing error title and description copy.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

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.
Frontend Architecture Contract ⚠️ Warning PR introduces new architectural pattern (GraphQL NOT_FOUND normalization) without updating docs/architecture/frontend.md to document the DataSource/ViewModel/UI contract. Add section to docs/architecture/frontend.md documenting isGraphQLNotFoundError pattern, DataSource NOT_FOUND→item:null mapping, ViewModel showNotFound getter, and error vs not-found UI separation.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: normalizing GraphQL not-found errors in detail responses across the codebase.
Linked Issues check ✅ Passed All coding requirements from issue #38 are met: isGraphQLNotFoundError helper added [graphqlErrors.ts], null-item mapping implemented across all detail data sources [6 updated], not-found UI states added to view models [3 updated], and non-404 errors preserved as error states.
Out of Scope Changes check ✅ Passed All changes directly support the #38 objectives: GraphQL not-found error detection and normalization, nullable item mapping, not-found UI rendering, and error preservation. No unrelated modifications detected.
Description check ✅ Passed PR description is well-structured with clear summary, validation steps performed, and issue reference. However, it lacks explicit coverage of the PR description template sections (Docs Source of Truth, Self-Review, Checks).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

@ilya-chizhov-a
ilya-chizhov-a force-pushed the fix/graphql-not-found-normalization branch from 7966791 to 5994e90 Compare May 22, 2026 16:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/pages/Locations/model/LocationDetailViewModel.ts`:
- Line 220: The return expression in LocationDetailViewModel uses a redundant
check: remove the unnecessary && !this.showNotFound from the guard (keep
Boolean(this.item) && !this.showError) because showNotFound is already derived
from !this.item; update the return in the getter/method that currently returns
"Boolean(this.item) && !this.showError && !this.showNotFound" to
"Boolean(this.item) && !this.showError" so behavior remains the same but the
condition is simplified.

In `@src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx`:
- Around line 40-46: The not-found branch is using generic error copy
(vm.copy.detail.errorTitle / errorDescription) which implies a failure; update
the not-found rendering to use dedicated not-found copy keys (e.g.,
vm.copy.detail.notFoundTitle and vm.copy.detail.notFoundDescription) in the
renderWhen(vm.showNotFound, <StatePanel ... />) call and update the ViewModel to
supply those keys; also add a safe fallback to the existing
errorTitle/errorDescription if the new notFound keys are not present to avoid
regressions.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 68681abd-948f-4617-a53f-2e788886987a

📥 Commits

Reviewing files that changed from the base of the PR and between 1eb0986 and 7966791.

📒 Files selected for processing (16)
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/shared/lib/helpers/graphqlErrors.ts
  • src/shared/lib/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.agents/skills/frontend-self-review/SKILL.md)

**/*.{ts,tsx}: React views should render observable state and forward events only, without managing state directly
Repeated rows/cards should use List and Item ViewModel boundaries when formatting, links, badges, actions, permissions, files, or computed labels are involved
Methods should stay at one abstraction level
One non-trivial React component should live in one file

**/*.{ts,tsx}: React components render observable model state and forward events only. ViewModels own page state, actions, derived values, transitions, and descriptors.
DataSources own GraphQL SDK calls, request lifecycle, response extraction, pagination, cancellation, and transport-level error mapping.
Small bootstrap pages may call ApiService directly until the page spec is marked Done. Pages marked Done must use a DataSource for non-trivial API access.
Keep methods at one abstraction level.

Files:

  • src/shared/lib/index.ts
  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/shared/lib/helpers/graphqlErrors.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (REVIEW.md)

Keep FSD dependencies one-way: app -> pages -> widgets/features/entities -> shared

Files:

  • src/shared/lib/index.ts
  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/shared/lib/helpers/graphqlErrors.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

src/**/*.{ts,tsx}: Prefer small methods with one abstraction level: public actions orchestrate; private helpers transform data, build variables, build item models, or map state, but not all at once
Shared or persisted state must be implemented with DI services or dedicated state ViewModels, not ad hoc module variables or direct browser storage calls in React components

Files:

  • src/shared/lib/index.ts
  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/shared/lib/helpers/graphqlErrors.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/*.ts

⚙️ CodeRabbit configuration file

src/**/*.ts: Review against REVIEW.md and docs/architecture/frontend.md.
Block architecture drift: React components must not fetch, build query variables,
own business state, perform business decisions, or access persisted/browser state
directly. Page state, actions, derived values, and ExplainerDescriptor construction
belong in ViewModels. Non-trivial API access belongs in DataSources, except
small bootstrap pages may call ApiService directly until the page spec is marked
Done. Repeated row/card/detail surfaces should use Item ViewModels when rows have
formatting, links, badges, actions, permissions, files, or computed labels.
Prefer MobX computed getters for values read by views. Methods should stay at
one abstraction level and separate orchestration, variable building, response
mapping, and display formatting.

Files:

  • src/shared/lib/index.ts
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/shared/lib/helpers/graphqlErrors.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/{pages,widgets,features}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

List/card/detail rendering must use explicit List ViewModel and Item ViewModel boundaries when rows need links, formatting, permissions, or actions

Files:

  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

API access for a non-trivial page must use a DataSource and not bypass it by talking directly to low-level clients from a component or large page ViewModel method

Files:

  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.agents/rules/frontend-mvvm-boundaries.mdc)

src/**/ui/**/*.{ts,tsx}: Use List ViewModel and Item ViewModel boundaries for non-trivial repeated rows/cards.
Prefer MobX computed getters for values read by views.

src/**/ui/**/*.{ts,tsx}: Frontend architecture contract: Keep React views thin, with state/actions/derived values owned by ViewModels
Frontend architecture contract: One non-trivial React component per file
Frontend architecture contract: Use same-named folders for non-test component files under src/**/ui/ with no component-folder index.ts barrels

Files:

  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
src/**/ui/*/*.{ts,tsx}

📄 CodeRabbit inference engine (.agents/rules/frontend-mvvm-boundaries.mdc)

Every non-test component file under src/**/ui/ must live in a same-named folder, for example ui/RegionCard/RegionCard.tsx. Do not add component-folder barrels such as ui/RegionCard/index.ts.

Files:

  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
src/**/*.tsx

⚙️ CodeRabbit configuration file

src/**/*.tsx: Review React components as thin observer views. They should render observable
model state and forward events to ViewModel actions only. Flag JSX that contains
request orchestration, filter/sort/query payload construction, link-building
decisions, business rules, direct storage/browser access, or raw GraphQL response
transformations. Enforce one non-trivial React component per file. Enforce
same-named folders for non-test component files under src/**/ui/ and reject
component-folder index.ts barrels.

Files:

  • src/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx
  • src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx
  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
**/*DataSource.{ts,tsx}

📄 CodeRabbit inference engine (.agents/skills/frontend-self-review/SKILL.md)

DataSources should own SDK calls, request lifecycle, response extraction, pagination, and transport-level error mapping

Files:

  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
src/**/*DataSource*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

DataSources own GraphQL SDK calls, request cancellation/reset, response extraction, pagination shape, and transport-level error mapping

Files:

  • src/pages/Parties/api/PartyDetailDataSource.ts
  • src/pages/Locations/api/LocationDetailDataSource.ts
  • src/pages/Heroes/api/HeroDetailDataSource.ts
  • src/pages/Regions/api/RegionDetailDataSource.ts
  • src/pages/Items/api/ItemDetailDataSource.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
  • src/pages/Monsters/api/MonsterDetailDataSource.ts
  • src/pages/Quests/api/QuestDetailDataSource.ts
**/*ViewModel.{ts,tsx}

📄 CodeRabbit inference engine (.agents/skills/frontend-self-review/SKILL.md)

**/*ViewModel.{ts,tsx}: ViewModels should own state, actions, derived values, transitions, and descriptors
Prefer computed getters for derived read models

Files:

  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
src/**/pages/**/*ViewModel*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

Page ViewModels own request lifecycle, filters, cursor, locale, state transitions, actions, derived values, and ExplainerDescriptor construction

Files:

  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
src/**/{model,viewModel}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

Favor computed getters for read models and avoid keeping duplicate mutable state when it can be derived from request data, filters, route params, or services

Files:

  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
src/**/*ViewModel*.{ts,tsx}

📄 CodeRabbit inference engine (REVIEW.md)

src/**/*ViewModel*.{ts,tsx}: Derived display state must be exposed as MobX computed getters where the value is read by the view, not recomputed imperatively
A ViewModel must not mix unrelated abstraction levels in the same method, such as request orchestration, GraphQL response parsing, URL building, and JSX display decisions in one block

Files:

  • src/pages/Locations/model/LocationDetailViewModel.ts
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Regions/model/RegionDetailViewModel.ts
🧠 Learnings (1)
📚 Learning: 2026-05-20T08:50:13.209Z
Learnt from: anton62k
Repo: revisium/demo-rpg-frontend PR: 31
File: src/pages/Npcs/model/NpcDetailViewModel.ts:167-172
Timestamp: 2026-05-20T08:50:13.209Z
Learning: When building navigation for NPC pages (catalog or detail) under `src/pages/Npcs/`, call `getSectionNavigationItems('heroes')`—do not call it with `'npcs'`. This is because `src/shared/config/navigation.ts`’s `SectionNavKey` only defines top-level groups (`heroes`, `items`, `quests`, `world`), and `npcs` is a sub-item inside the `heroes` group.

Applied to files:

  • src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx
  • src/pages/Npcs/model/NpcDetailViewModel.ts
  • src/pages/Npcs/api/NpcDetailDataSource.ts
🔇 Additional comments (15)
src/pages/Heroes/api/HeroDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 6-6, 9-9, 30-30

src/pages/Items/api/ItemDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 9-9, 24-30

src/pages/Monsters/api/MonsterDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 10-10, 25-31

src/pages/Parties/api/PartyDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 9-9, 24-30

src/pages/Quests/api/QuestDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 10-10, 25-31

src/pages/Npcs/api/NpcDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 8-8, 23-29

src/pages/Npcs/model/NpcDetailViewModel.ts (1)

163-165: LGTM!

Also applies to: 168-168

src/pages/Npcs/ui/NpcDetailPage/NpcDetailPage.tsx (1)

39-45: LGTM!

src/pages/Regions/api/RegionDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 8-8, 23-29

src/pages/Regions/model/RegionDetailViewModel.ts (1)

178-180: LGTM!

Also applies to: 183-183

src/pages/Regions/ui/RegionDetailPage/RegionDetailPage.tsx (1)

39-45: LGTM!

src/shared/lib/helpers/graphqlErrors.ts (1)

1-27: LGTM!

src/shared/lib/index.ts (1)

47-47: LGTM!

src/pages/Locations/api/LocationDetailDataSource.ts (1)

2-2: LGTM!

Also applies to: 5-5, 8-8, 23-29

src/pages/Locations/model/LocationDetailViewModel.ts (1)

215-217: LGTM!


public get showDetail(): boolean {
return Boolean(this.item) && !this.showError;
return Boolean(this.item) && !this.showError && !this.showNotFound;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

The !this.showNotFound check is redundant.

The condition Boolean(this.item) already guarantees showNotFound will be false, since showNotFound requires !this.item. These are mutually exclusive states.

♻️ Simplify the guard
  public get showDetail(): boolean {
-   return Boolean(this.item) && !this.showError && !this.showNotFound;
+   return Boolean(this.item) && !this.showError;
  }
🤖 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/pages/Locations/model/LocationDetailViewModel.ts` at line 220, The return
expression in LocationDetailViewModel uses a redundant check: remove the
unnecessary && !this.showNotFound from the guard (keep Boolean(this.item) &&
!this.showError) because showNotFound is already derived from !this.item; update
the return in the getter/method that currently returns "Boolean(this.item) &&
!this.showError && !this.showNotFound" to "Boolean(this.item) &&
!this.showError" so behavior remains the same but the condition is simplified.

Comment on lines +40 to +46
{renderWhen(
vm.showNotFound,
<StatePanel
description={vm.copy.detail.errorDescription}
title={vm.copy.detail.errorTitle}
/>,
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Not-found state uses generic error copy.

The not-found panel renders vm.copy.detail.errorTitle and vm.copy.detail.errorDescription, which are designed for generic errors. A missing resource is a normal state, not an error condition, and should explain that the location wasn't found rather than suggesting something went wrong.

Consider adding dedicated not-found copy in the ViewModel's copy structure, such as vm.copy.detail.notFoundTitle and vm.copy.detail.notFoundDescription, to provide clearer user feedback that differentiates this state from actual errors.

🤖 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/pages/Locations/ui/LocationDetailPage/LocationDetailPage.tsx` around
lines 40 - 46, The not-found branch is using generic error copy
(vm.copy.detail.errorTitle / errorDescription) which implies a failure; update
the not-found rendering to use dedicated not-found copy keys (e.g.,
vm.copy.detail.notFoundTitle and vm.copy.detail.notFoundDescription) in the
renderWhen(vm.showNotFound, <StatePanel ... />) call and update the ViewModel to
supply those keys; also add a safe fallback to the existing
errorTitle/errorDescription if the new notFound keys are not present to avoid
regressions.

@ilya-chizhov-a
ilya-chizhov-a force-pushed the fix/graphql-not-found-normalization branch 3 times, most recently from 8a4e1b8 to 5a5c47c Compare May 22, 2026 16:18
@ilya-chizhov-a
ilya-chizhov-a force-pushed the fix/graphql-not-found-normalization branch from 5a5c47c to a2a1bb6 Compare May 22, 2026 16:21
@sonarqubecloud

Copy link
Copy Markdown

@ilya-chizhov-a

Copy link
Copy Markdown
Author

Ready for review.

Validation passed locally:

  • npm run ts:check
  • npm run lint:ci
  • npm run ui:lint
  • $env:CHOKIDAR_USEPOLLING='1'; npx steiger src
  • npm run build
  • git diff --check

GitHub CI, SonarCloud, and CodeRabbit are green. The PR fixes the generated GraphQL NOT_FOUND normalization for the reproduced Regions detail route and existing detail pages with not-found state while preserving non-404 errors.

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.

Normalize generated GraphQL NOT_FOUND errors in detail views

1 participant