Skip to content

fix(ui): make live panel toggles consistent - #1319

Closed
4gray wants to merge 16 commits into
masterfrom
agent/live-panel-toggle-consistency-2
Closed

fix(ui): make live panel toggles consistent#1319
4gray wants to merge 16 commits into
masterfrom
agent/live-panel-toggle-consistency-2

Conversation

@4gray

@4gray 4gray commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • Give Groups and Channels independent persisted intent with a shared LiveLayoutPanelStateService and idempotent migration from live-sidebar-state.
  • Make M3U, Xtream, Stalker, Favorites, and Recent disclosures consistent across normal, loading, empty, zero-result, and responsive layouts, including focus transfer, inert, ARIA ownership/state, 40px targets, and temporary Cmd/Ctrl+B suppression.
  • Show the Guide disclosure only beside a working inline player; external MPV/VLC keeps static EPG and radio keeps no Guide action.

Verification

  • 1,940 affected unit tests passed across the state, shell, M3U, portal, EPG, component, and playback projects.
  • All 11 affected lint targets passed (existing unrelated warnings remain).
  • pnpm nx build web passed.
  • Electron E2E: live-panel-toggles.e2e.ts passed 3/3 for M3U, Xtream, and Stalker, including migration, persistence, mobile suppression, accessibility, zero results, external playback, and radio.
  • i18n:check, release-note validation, skill validation, Prettier, and git diff --check passed.
  • Electron CDP visual/accessibility review covered M3U, Xtream, Stalker, Favorites, Recent, desktop/mobile, dark/light, restore ordering, focus, and target sizing.

Scope boundaries

Refs #1118

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces independent persisted Groups and Channels intent and makes live-layout disclosures consistent.

  • Adds a shared panel-state service with legacy-state migration and temporary shortcut suppression.
  • Updates M3U, Xtream, Stalker, Favorites, Recent, workspace, loading, empty, responsive, and EPG layouts with disclosure, focus, inert, and ARIA behavior.
  • Adds broad unit and Electron end-to-end coverage, translations, architecture documentation, and a release note.

Confidence Score: 4/5

The cross-route suppression leak should be fixed before merging because a shortcut on one live surface can unexpectedly hide panels on the next surface.

Temporary master suppression is held by a root singleton and is consumed by every live layout, but no navigation or component lifecycle clears it; the M3U All view also introduces a non-blocking duplicate panel ID.

Files Needing Attention: libs/portal/shared/data-access/src/lib/live-layout-panel-state.service.ts; libs/ui/components/src/lib/channel-list-container/all-channels-view/all-channels-view.component.ts

Important Files Changed

Filename Overview
libs/portal/shared/data-access/src/lib/live-layout-panel-state.service.ts Adds independent persisted panel intent and migration, but temporary master suppression leaks across routed live layouts.
libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.ts Integrates independent panel state, responsive suppression, focus transfer, and shortcut handling into the M3U player.
libs/ui/components/src/lib/channel-list-container/all-channels-view/all-channels-view.component.ts Adds Channels disclosure ownership, but duplicates the controlled panel ID already assigned by the parent M3U sidebar.
libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.ts Adds independent Channels visibility, Groups-aware shortcut suppression, focus transfer, and inline-player Guide capability.
libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts Applies the same panel and Guide behavior to Stalker TV and radio layouts.
libs/portal/shared/ui/src/lib/components/unified-collection/unified-collection-page.component.ts Makes the collection header the sole Channels disclosure owner across loading, empty, and zero-result states.
apps/electron-backend-e2e/src/live-panel-toggles.e2e.ts Adds cross-provider Electron coverage for migration, persistence, accessibility, responsive behavior, external playback, and radio.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  User[Panel action or Cmd/Ctrl+B] --> State[LiveLayoutPanelStateService]
  State --> Intent[Persisted Groups and Channels intent]
  State --> Suppression[Temporary master suppression]
  Intent --> M3U[M3U layout]
  Intent --> Portal[Xtream and Stalker layouts]
  Intent --> Collections[Favorites and Recent]
  Suppression --> M3U
  Suppression --> Portal
  Suppression --> Collections
  M3U --> Panels[Effective Groups and Channels visibility]
  Portal --> Panels
  Collections --> Panels
Loading
Prompt To Fix All With AI
### Issue 1
libs/portal/shared/data-access/src/lib/live-layout-panel-state.service.ts:64-72
**Master suppression leaks across routes**

When a user presses Cmd/Ctrl+B and then navigates to another live surface, the root-scoped `masterSuppressed` state remains active, causing the destination's applicable Groups and Channels panels to stay hidden until another shortcut or direct panel action clears it.

### Issue 2
libs/ui/components/src/lib/channel-list-container/all-channels-view/all-channels-view.component.ts:44-46
**Duplicate Channels panel ID**

The M3U All view assigns `live-channels-panel` to both the outer collapsible sidebar and this nested component host, leaving the new ARIA relationship and ID-based DOM or accessibility lookups with two targets.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(ui): ignore hidden panels in master ..." | Re-trigger Greptile

Comment on lines +64 to +72
toggleMasterSuppression(
effectivelyVisiblePanels: readonly LiveLayoutPanel[]
): void {
if (this._masterSuppressed()) {
this._masterSuppressed.set(false);
return;
}

this._masterSuppressed.set(effectivelyVisiblePanels.length > 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Master suppression leaks across routes

When a user presses Cmd/Ctrl+B and then navigates to another live surface, the root-scoped masterSuppressed state remains active, causing the destination's applicable Groups and Channels panels to stay hidden until another shortcut or direct panel action clears it.

Context Used: CLAUDE.md (source)

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: libs/portal/shared/data-access/src/lib/live-layout-panel-state.service.ts
Line: 64-72

Comment:
**Master suppression leaks across routes**

When a user presses Cmd/Ctrl+B and then navigates to another live surface, the root-scoped `masterSuppressed` state remains active, causing the destination's applicable Groups and Channels panels to stay hidden until another shortcut or direct panel action clears it.

**Context Used:** CLAUDE.md ([source](https://github.com/4gray/iptvnator/blob/master/CLAUDE.md))

**Knowledge Base Used:**
- [Web Frontend App (apps/web)](https://app.greptile.com/iptvnator/-/custom-context/knowledge-base/4gray/iptvnator/-/docs/web-frontend-app.md)
- [Xtream Codes and Stalker Portal Integration](https://app.greptile.com/iptvnator/-/custom-context/knowledge-base/4gray/iptvnator/-/docs/portal-xtream-stalker.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +44 to +46
host: {
id: 'live-channels-panel',
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Duplicate Channels panel ID

The M3U All view assigns live-channels-panel to both the outer collapsible sidebar and this nested component host, leaving the new ARIA relationship and ID-based DOM or accessibility lookups with two targets.

Knowledge Base Used: Web Frontend App (apps/web)

Prompt To Fix With AI
This is a comment left during a code review.
Path: libs/ui/components/src/lib/channel-list-container/all-channels-view/all-channels-view.component.ts
Line: 44-46

Comment:
**Duplicate Channels panel ID**

The M3U All view assigns `live-channels-panel` to both the outer collapsible sidebar and this nested component host, leaving the new ARIA relationship and ID-based DOM or accessibility lookups with two targets.

**Knowledge Base Used:** [Web Frontend App (apps/web)](https://app.greptile.com/iptvnator/-/custom-context/knowledge-base/4gray/iptvnator/-/docs/web-frontend-app.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18c82144a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +384 to +386
readonly isAllChannelsPanelCollapsed = computed(
() => this.activeView() === 'all' && !this.channelsPanelExpanded()
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reclaim the outer M3U sidebar when both panels are hidden

In the M3U Groups view, Cmd/Ctrl+B makes both effective panel inputs false, but this computed state only collapses the outer sidebar for the all view. The outer element therefore retains its persisted pixel width while both child panels have width zero, leaving a large blank column and continuing to constrain the player; the same occurs on mobile after Groups is responsively suppressed and Channels is hidden. Account for the grouped state by shrinking the outer container to its available restore rails when neither panel is expanded.

Useful? React with 👍 / 👎.

Comment on lines +44 to +46
host: {
id: 'live-channels-panel',
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the M3U Channels panel ID unique

When the M3U All Channels view renders, this host receives id="live-channels-panel" while its newly changed parent sidebar receives the same ID. The hide and restore controls' aria-controls value consequently resolves to a non-unique target, making the disclosure relationship ambiguous to assistive technology and any DOM code using ID lookup. Assign the ID to only one element representing the collapsible panel.

Useful? React with 👍 / 👎.

@4gray 4gray closed this Aug 1, 2026
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.

1 participant