fix(settings): close the M3U group editor on any relock

The group management dialog lists every group name, locked ones
included, even when it opened without lock toggles (unreadable lock
store). It now closes on any relock, and the groups view re-checks the
lock state before opening it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-09-27 16:15:02 +02:00
1 parent b078526bef
commit 0f5276c581
5 files changed
+38 -6

No files matched your search

@@ -55,13 +55,21 @@ describe('GroupManagementDialogComponent', () => {
expect(dialogRef.close).toHaveBeenCalledWith(undefined);
});
it('keeps the plain hide/show editor open when the lock feature is off', async () => {
it('keeps the plain hide/show editor open while nothing relocks', async () => {
const fixture = await create({ groups, hiddenGroupTitles: ['News'] });
parentalLock.active.set(true);
fixture.detectChanges();
expect(dialogRef.close).not.toHaveBeenCalled();
expect(fixture.componentInstance.showLocks).toBe(false);
});
it('closes the editor without lock toggles too on a relock: it lists every group', async () => {
// Opened without toggles because the lock store was unreadable.
const fixture = await create({ groups, hiddenGroupTitles: ['News'] });
parentalLock.active.set(true);
fixture.detectChanges();
expect(dialogRef.close).toHaveBeenCalledWith(undefined);
});
});
@@ -105,9 +105,10 @@ export class GroupManagementDialogComponent {
constructor() {
// A relock while the editor is open: the locked group names it
// lists and the lock list it can rewrite are behind the PIN.
// lists (with or without lock toggles — every group is listed) and
// the lock list it can rewrite are behind the PIN.
effect(() => {
if (this.showLocks && this.parentalLock.active()) {
if (this.parentalLock.active()) {
this.dialogRef.close(undefined);
}
});
@@ -51,6 +51,7 @@ describe('GroupsViewComponent', () => {
requestUnlock: jest.Mock;
ensureLocksReadable: jest.Mock;
lockedGroupTitles: jest.Mock;
active: jest.Mock;
};
const sportsCenter = createChannel(
@@ -112,6 +113,7 @@ describe('GroupsViewComponent', () => {
requestUnlock: jest.fn().mockResolvedValue(true),
ensureLocksReadable: jest.fn().mockResolvedValue(true),
lockedGroupTitles: jest.fn(() => ['News']),
active: jest.fn(() => false),
};
dialog = {
@@ -558,6 +560,20 @@ describe('GroupsViewComponent', () => {
expect(data.lockedGroupTitles).toBeUndefined();
});
it('opens no manage-groups dialog when the session relocked while the store was read', async () => {
fixture.componentRef.setInput('playlistId', 'playlist-a');
fixture.componentRef.setInput('lockedGroupTitles', []);
fixture.detectChanges();
parentalLock.ensureLocksReadable.mockImplementation(async () => {
parentalLock.active.mockReturnValue(true);
return true;
});
await component.openGroupManagement();
expect(dialog.open).not.toHaveBeenCalled();
});
it('drops the manage-groups result once another playlist is open', async () => {
const hiddenGroupTitlesChanged = jest.fn();
const lockedGroupTitlesChanged = jest.fn();
@@ -567,6 +567,11 @@ export class GroupsViewComponent {
this.playlistId() === playlistId
? this.parentalLock.lockedGroupTitles(playlistId)
: null;
// Relocked while the store was being read: the dialog lists every
// group, locked ones included.
if (this.parentalLock.active() || this.playlistId() !== playlistId) {
return;
}
const dialogRef = this.dialog.open(GroupManagementDialogComponent, {
data: {
groups,