Skip to content

fix(metadata): hide sidecar tab when sidecar json is disabled#814

Open
zachyale wants to merge 1 commit intodevelopfrom
fix/disable-sidecar-tab-via-settings
Open

fix(metadata): hide sidecar tab when sidecar json is disabled#814
zachyale wants to merge 1 commit intodevelopfrom
fix/disable-sidecar-tab-via-settings

Conversation

@zachyale
Copy link
Copy Markdown
Member

@zachyale zachyale commented Apr 23, 2026

Description

Currently, Sidecar tab is gated by user permissions, is physical and is local, but not if Sidecar is enabled or not. Hide the Sidecar tab in the book details metadata center when Enable Sidecar JSON is disabled.

Linked Issue: Fixes #810

Changes

  • hide sidecar tab visibility on existing sidecar logic && [...].sidecarSettings.enabled

Note: In testing this, I found that setting the URL param for the view to a view a user doesn't have permissions for just shows an empty screen. Created a follow up outside of this PR on #813

Summary by CodeRabbit

  • Refactor
    • Improved sidecar metadata tab visibility controls using configuration-based logic.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

📝 Walkthrough

Walkthrough

The changes introduce a computed canShowSidecarTab getter to control sidecar tab visibility in book metadata view, based on settings and user permissions. The template now uses this single boolean instead of complex conditional logic. Tests verify the visibility toggle when sidecar settings are enabled or disabled.

Changes

Cohort / File(s) Summary
Sidecar Tab Visibility Control
frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html, book-metadata-center.component.ts, book-metadata-center.component.spec.ts
Adds canShowSidecarTab computed getter combining sidecar settings enabled state with user permissions (admin or canEditMetadata) and environment constraints (!isPhysical and isLocalStorage). Template conditional simplified to use new getter. Comprehensive unit tests verify visibility behavior when sidecar settings toggle.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

frontend, enhancement

Suggested reviewers

  • imajes
  • balazs-szucs

Poem

🐰 A curious rabbit hopped through the code,
And found where the sidecar tab strode,
Now settings control what users can see,
When JSON's disabled, the tab won't be free! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows conventional commit format with fix type and descriptive scope about hiding sidecar tab based on settings.
Description check ✅ Passed The description includes problem statement, linked issue, and specific implementation details about the changes required.
Linked Issues check ✅ Passed Changes implement the requirement from #810 by adding conditional logic to hide sidecar tab when sidecar JSON setting is disabled.
Out of Scope Changes check ✅ Passed All changes are scoped to the sidecar tab visibility logic and related tests; no unrelated modifications detected.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/disable-sidecar-tab-via-settings
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/disable-sidecar-tab-via-settings

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.

Copy link
Copy Markdown
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.

🧹 Nitpick comments (2)
frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts (1)

89-94: Consider a computed signal for reactivity.

canShowSidecarTab is a plain getter that reads a signal (appSettings()) plus plain fields (admin, canEditMetadata, isLocalStorage). It works today because the template re-evaluates on change detection, but expressing it as a computed() would make it properly reactive to settings changes and align with the team's signal-first pattern—especially if admin/canEditMetadata/isLocalStorage are ever migrated to signals (note isLocalStorage is currently only assigned once in ngOnInit, so it won't react to later diskType changes).

Based on learnings: prefer Angular signals (signal/computed) over imperative patterns where they fit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts`
around lines 89 - 94, Replace the plain getter canShowSidecarTab with an Angular
computed signal so its value updates reactively when appSettings() or any future
signals (admin, canEditMetadata, isLocalStorage) change: create a computed that
reads this.appSettingsService.appSettings() and the component fields (admin,
canEditMetadata, isPhysical, isLocalStorage) and returns the same boolean
expression currently in the getter; update template bindings to use the computed
value and remove the getter; if isLocalStorage is set only in ngOnInit consider
converting it to a signal or updating it through a signal source so the computed
reacts to diskType changes.
frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts (1)

37-50: Test coverage is narrow — consider covering permission/physical/localStorage gates.

The suite only toggles sidecarEnabled. Since canShowSidecarTab also depends on (admin || canEditMetadata), !isPhysical, and isLocalStorage, a regression in any of those conditions would not be caught. Also note that ngOnInit is never invoked here, so isLocalStorage stays at its field default (true) and diskType in buildSettings is effectively unexercised — a future refactor that moves isLocalStorage derivation out of ngOnInit could silently change behavior without failing this spec.

Consider adding cases for: user without admin/canEditMetadata, a physical book, and non-LOCAL disk type.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts`
around lines 37 - 50, The test only toggles sidecarEnabled and never exercises
the other gates used by BookMetadataCenterComponent.canShowSidecarTab; update
the spec to call ngOnInit and add cases that toggle user permissions (admin and
canEditMetadata), physical/disk type variations (isPhysical/diskType in
buildSettings) and isLocalStorage to cover all branches: create instances via
TestBed.runInInjectionContext(() => new BookMetadataCenterComponent()), call
component.ngOnInit(), then set appSettingsSignal with buildSettings variations
(sidecarEnabled true/false, diskType set to physical/non-LOCAL) and adjust the
user/permission signal or input to simulate admin=false and
canEditMetadata=false to assert canShowSidecarTab false, and assert true only
when sidecarEnabled + (admin||canEditMetadata) + !isPhysical + isLocalStorage
are satisfied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts`:
- Around line 37-50: The test only toggles sidecarEnabled and never exercises
the other gates used by BookMetadataCenterComponent.canShowSidecarTab; update
the spec to call ngOnInit and add cases that toggle user permissions (admin and
canEditMetadata), physical/disk type variations (isPhysical/diskType in
buildSettings) and isLocalStorage to cover all branches: create instances via
TestBed.runInInjectionContext(() => new BookMetadataCenterComponent()), call
component.ngOnInit(), then set appSettingsSignal with buildSettings variations
(sidecarEnabled true/false, diskType set to physical/non-LOCAL) and adjust the
user/permission signal or input to simulate admin=false and
canEditMetadata=false to assert canShowSidecarTab false, and assert true only
when sidecarEnabled + (admin||canEditMetadata) + !isPhysical + isLocalStorage
are satisfied.

In
`@frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts`:
- Around line 89-94: Replace the plain getter canShowSidecarTab with an Angular
computed signal so its value updates reactively when appSettings() or any future
signals (admin, canEditMetadata, isLocalStorage) change: create a computed that
reads this.appSettingsService.appSettings() and the component fields (admin,
canEditMetadata, isPhysical, isLocalStorage) and returns the same boolean
expression currently in the getter; update template bindings to use the computed
value and remove the getter; if isLocalStorage is set only in ngOnInit consider
converting it to a signal or updating it through a signal source so the computed
reacts to diskType changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3364c57e-b149-421f-9d73-b42e71caaab9

📥 Commits

Reviewing files that changed from the base of the PR and between 03389d7 and 40bb32a.

📒 Files selected for processing (3)
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Suite / Frontend Tests
  • GitHub Check: Test Suite / Backend Tests
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Frontend Lint Threshold Check
🧰 Additional context used
📓 Path-based instructions (5)
frontend/src/**/*.{ts,tsx,html,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indentation in TypeScript, HTML, and SCSS in frontend code

Files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
frontend/src/**/*.component.ts

📄 CodeRabbit inference engine (AGENTS.md)

Keep Angular code on standalone components. Do not add NgModules in frontend code

Files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer inject() over constructor injection in frontend code

Files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
frontend/src/**/*.{ts,tsx,html}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx,html}: Follow frontend/eslint.config.js: component selectors use app-, directive selectors use app, and any is disallowed in frontend code
Put user-facing strings in Transloco files under frontend/src/i18n/

Files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
frontend/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest for tests in frontend code

Files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
🧠 Learnings (5)
📚 Learning: 2026-04-04T14:03:28.295Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 372
File: frontend/src/app/features/book/service/app-books-api.service.ts:150-178
Timestamp: 2026-04-04T14:03:28.295Z
Learning: In `frontend/src/app/features/book/service/app-books-api.service.ts`, the `summaryToBook` function intentionally uses `as unknown as Book` to cast a partial object to the `Book` type. The returned object omits some required `Book` fields (e.g. `metadata.bookId`, `pdfProgress.page`) and includes an extra `bookFiles: []` property not in the `Book` interface. This is by design — consumers of `AppBooksApiService.books()` (e.g. `BookCardComponent`) only access the subset of properties that are populated from `AppBookSummary`, so no runtime issues occur. Do not flag this as a type safety error.

Applied to files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
📚 Learning: 2026-04-05T21:16:01.715Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 385
File: frontend/src/app/app.component.ts:55-56
Timestamp: 2026-04-05T21:16:01.715Z
Learning: When reviewing code in the Grimmory frontend (Angular), prefer modern Angular patterns. Specifically: (1) Prefer `DestroyRef` with `takeUntilDestroyed(destroyRef)` for teardown in Angular v16+ instead of manually tracking `Subscription` arrays and calling `unsubscribe()` in `ngOnDestroy()`. (2) Prefer `inject()` for dependency injection over constructor injection where appropriate. (3) Prefer Angular signals (e.g., `signal`, `computed`) over `BehaviorSubject`/`Observable` for state where signals/computed values fit the use case. Flag older patterns when they can be replaced with these modern equivalents without changing behavior.

Applied to files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
📚 Learning: 2026-04-07T09:28:09.587Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 393
File: frontend/src/app/features/readers/pdf-reader/pdf-reader.component.ts:255-263
Timestamp: 2026-04-07T09:28:09.587Z
Learning: In this Angular frontend (under frontend/src/app/), flag manual resource management/cleanup patterns when there is an Angular v16+ automatic alternative. Examples to prefer: (1) Instead of manually pairing document/window event listeners with stored cleanup functions (e.g., add/removeEventListener with mouseMoveCleanup/documentClickCleanup/keydownCleanup/touchCleanup fields), register teardown via DestroyRef.onDestroy(cleanupFn) (or equivalent Angular v16+ teardown mechanism). (2) Instead of storing Subscriptions in fields and explicitly unsubscribing in ngOnDestroy (e.g., annotationSaveSubscription/annotationCacheSubscription), use takeUntilDestroyed(destroyRef) (piped into the observable) or other Angular v16+ primitives. (3) If teardown is lifecycle-coupled and can be automated via DestroyRef/takeUntilDestroyed/signals (or other Angular v16+ mechanisms), prefer the automated approach over manual ngOnDestroy cleanup. Raise a review finding for the manual pattern and recommend the aut...

Applied to files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
📚 Learning: 2026-04-11T03:55:57.229Z
Learnt from: zachyale
Repo: grimmory-tools/grimmory PR: 439
File: frontend/src/app/features/series-browser/components/series-browser/series-browser.component.ts:178-196
Timestamp: 2026-04-11T03:55:57.229Z
Learning: In this Angular frontend (frontend/src/app/), prefer the team’s reactive i18n “signal/computed” pattern: (1) For individual reactive translated strings, use `translateSignal()` from `jsverse/transloco`. (2) For option/label arrays that must update on language switch, create a single `activeLang` signal with `toSignal(t.langChanges$, { initialValue: t.getActiveLang() })`, then derive the arrays as `computed()` signals that read `activeLang()`. This should avoid manual `langChanges$` subscriptions and any `ngOnDestroy` subscription cleanup; prefer this over subscribing in `ngOnInit` when implementing reactive localization.

Applied to files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.ts
  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
📚 Learning: 2026-04-22T01:56:39.495Z
Learnt from: CR
Repo: grimmory-tools/grimmory PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-22T01:56:39.495Z
Learning: Applies to frontend/src/**/*.{test,spec}.{ts,tsx} : Use Vitest for tests in frontend code

Applied to files:

  • frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.spec.ts
🔀 Multi-repo context grimmory-tools/grimmory-docs

[::grimmory-tools/grimmory-docs::] docs/metadata/metadata-settings.md — multiple sections describe "Sidecar JSON Files" and the Metadata Persistence settings page where "Enable Sidecar JSON" is documented (UI text, images, and behavior). Relevant lines: mentions enabling/disabling writing sidecar JSON alongside books and bulk export/import controls.

[::grimmory-tools/grimmory-docs::] docs/metadata/metadata-center.md — documents the Metadata Center UI including a Sidecar section/tab (images and descriptions of Export/Import, sync status, and that tabs shown depend on the book). Relevant lines: describes Sidecar tab content and that tabs depend on book type.

[::grimmory-tools/grimmory-docs::] docs/metadata/sidecar-files.md — details sidecar file purpose, export/import actions, write-on-update/write-on-scan options, and UI elements (Export/Import, sync badge).

[::grimmory-tools/grimmory-docs::] docs/metadata/metadata-fetch-configuration.md — references sidecar export/import buttons at library level and sidecar-related bulk operations.

Summary / impact:

  • The docs confirm a user-facing "Enable Sidecar JSON" setting and numerous UI references to a Sidecar tab/feature. Hiding the Sidecar tab when sidecar JSON is disabled aligns with documented settings and UI behavior; no other repos were available to search. This documentation should be updated if the UI behavior (tab visibility) changes in a way that needs mention.
🔇 Additional comments (1)
frontend/src/app/features/metadata/component/book-metadata-center/book-metadata-center.component.html (1)

40-45: LGTM — single source of truth for sidecar visibility.

Both the tab header and panel gate on canShowSidecarTab, so they cannot diverge.

Also applies to: 66-70

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hide the sidecar tab in book details when "Enable Sidecar JSON" is disabled

1 participant