mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-16 14:16:16 -08:00
feat(sources): rebuild the Sources page on the shared source row
- Side list (UI-kit side list): title with the playlist count and an Add button, a Type group, and on desktop a Status group (Any / Responding / Not responding). The two filters combine and persist; each group counts within the other's choice. The chosen row uses one selected-row token (soft tint, outlined in light theme). - Page: a 28px title with the visible count instead of the bordered header bar; Clean up and the sort menu are secondary buttons. Clean up shows how many sources do not respond. Sort adds Last updated, Most channels and (desktop) Not responding first, and keeps Name Z-A and Custom order. - List: app-source-row with hover actions (Refresh, Edit, ⋯); a failing row keeps Retry in view. "No matches" offers Reset filters. Dragging in custom order no longer reuses positions of rows a filter hides. - Delete with Undo: no confirmation; the row leaves at once and the delete runs when the toast closes (its close button commits at once). Deleting the active source switches to the next row. A large Xtream delete shows its row as "Removing…" with progress and Cancel, as before. - The list's refresh flows moved into SourceListRefreshService; E2E and performance drivers follow the new markup and delete flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
028a3db880
commit
401295c092
70 files changed
+3837
-2023
No files matched your search
@@ -111,16 +111,12 @@ test('@a11y icon-only buttons are named in Sources and the playlist info dialog'
|
||||
}) => {
|
||||
await addM3uUrlPlaylist(page, M3U_TITLE);
|
||||
|
||||
// Sources list: refresh, details and remove on each row.
|
||||
// Sources list: refresh, edit and the actions menu on each row.
|
||||
await openSources(page);
|
||||
const row = sourceRowByTitle(page, M3U_TITLE);
|
||||
await expect(row).toBeVisible({ timeout: 15_000 });
|
||||
await row.hover();
|
||||
for (const name of [
|
||||
'Refresh playlist',
|
||||
'Show playlist details',
|
||||
'Remove playlist',
|
||||
]) {
|
||||
for (const name of ['Refresh playlist', 'Edit…', 'Playlist actions']) {
|
||||
await expect(row.getByRole('button', { name })).toBeAttached();
|
||||
}
|
||||
await expectNamedButtons(page, 3);
|
||||
|
||||
@@ -259,7 +259,7 @@ test('@self-hosted M3U User-Agent reaches the provider on import and refresh', a
|
||||
channel = 'Refreshed UA Channel';
|
||||
const row = sourceRowByTitle(page, 'Protected M3U');
|
||||
await row.hover();
|
||||
await row.locator('.refresh-btn').click();
|
||||
await row.locator('.source-row__refresh').click();
|
||||
await expect(
|
||||
page.locator('.mat-mdc-snack-bar-label').last()
|
||||
).toContainText('updated');
|
||||
|
||||
@@ -190,7 +190,10 @@ export async function openSources(page: Page): Promise<void> {
|
||||
}
|
||||
|
||||
export function sourceRowByTitle(page: Page, title: string): Locator {
|
||||
return page.locator('app-playlist-item').filter({ hasText: title }).first();
|
||||
return page
|
||||
.locator('app-workspace-sources app-source-row')
|
||||
.filter({ hasText: title })
|
||||
.first();
|
||||
}
|
||||
|
||||
export async function openSourceEditor(
|
||||
@@ -200,7 +203,7 @@ export async function openSourceEditor(
|
||||
const row = sourceRowByTitle(page, title);
|
||||
await expect(row).toBeVisible({ timeout: 15_000 });
|
||||
await row.hover();
|
||||
await row.locator('.edit-btn').click();
|
||||
await row.locator('.source-row__edit').click();
|
||||
const dialog = page.locator('mat-dialog-container').last();
|
||||
await expect(dialog).toBeVisible();
|
||||
return dialog;
|
||||
|
||||
Reference in new issue
Block a user