diff --git a/web/e2e/task-3589-mobile-saved-views.spec.ts b/web/e2e/task-3589-mobile-saved-views.spec.ts new file mode 100644 index 000000000..79b9c56e1 --- /dev/null +++ b/web/e2e/task-3589-mobile-saved-views.spec.ts @@ -0,0 +1,49 @@ +import { test, expect } from './fixtures'; +import { browserLogin } from './lib/collab-helpers'; +import { authJson } from './lib/attachment-viewer'; + +/** + * TASK-3589: a saved view can be selected on a phone. The mobile "Choose view" + * sheet listed only List, Board and Table; saved views and "All" lived only in + * the desktop menu, so a saved workflow vanished at phone width. Selecting is + * the scope here; managing views stays on the desktop. + */ +test('the mobile view sheet lists saved views; picking one applies its filters, "All" clears them', async ({ page, fixture, request }, testInfo) => { + test.skip(testInfo.project.name !== 'mobile-chromium', 'the mobile sheet'); + // A word the list search matches (a bare number is not tokenized as one). + const stamp = `zqv${Date.now().toString(36)}`; + const ws = fixture.workspaceSlug; + const mk = async (title: string, priority: string) => { + const r = await request.post(`/api/v1/workspaces/${ws}/collections/tasks/items`, { + headers: authJson(fixture), + data: { title, fields: JSON.stringify({ status: 'open', priority }) }, + }); + expect(r.ok(), await r.text()).toBeTruthy(); + }; + await mk(`B3589 high ${stamp}`, 'high'); + await mk(`B3589 low ${stamp}`, 'low'); + const viewName = `Hot ${stamp}`; + const v = await request.post(`/api/v1/workspaces/${ws}/collections/tasks/views`, { + headers: authJson(fixture), + data: { name: viewName, view_type: 'list', config: JSON.stringify({ filters: [{ field: 'priority', op: 'eq', value: 'high' }] }) }, + }); + expect(v.ok(), await v.text()).toBeTruthy(); + + await browserLogin(page); + await page.goto(`/${fixture.adminUsername}/${ws}/tasks?view=list&q=${stamp}`); + await expect(page.getByText(`B3589 low ${stamp}`)).toBeVisible({ timeout: 15_000 }); + + await page.locator('button.view-chip').click(); + const sheet = page.getByRole('dialog', { name: 'Choose view' }); + await expect(sheet.getByText('Saved views')).toBeVisible(); + await sheet.getByRole('button', { name: viewName }).click(); + await expect(sheet).toBeHidden(); + await expect(page.getByText(`B3589 low ${stamp}`)).toHaveCount(0); + await expect(page.getByText(`B3589 high ${stamp}`)).toBeVisible(); + await expect(page).toHaveURL(/priority=high/); + + // "All" clears the view's filters again. + await page.locator('button.view-chip').click(); + await page.getByRole('dialog', { name: 'Choose view' }).getByRole('button', { name: 'All', exact: true }).click(); + await expect(page.getByText(`B3589 low ${stamp}`)).toBeVisible(); +}); diff --git a/web/src/lib/eachKeyCensus.ts b/web/src/lib/eachKeyCensus.ts index 701118346..7a62d4ca2 100644 --- a/web/src/lib/eachKeyCensus.ts +++ b/web/src/lib/eachKeyCensus.ts @@ -206,6 +206,7 @@ export const EACH_KEY_CENSUS: Record☷ Table + + {#if savedViews.length > 0} +
Saved views
+ + {#each savedViews as view (view.id)} + + {/each} + {/if} {/if} @@ -5088,6 +5121,15 @@ font-weight: 600; } + /* TASK-3589: the saved-views group in the mobile view sheet. */ + .view-sheet-label { + padding: var(--space-3) var(--space-3) var(--space-1); + font-size: 0.8em; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.04em; + } + .view-sheet-icon { font-size: 1.1em; width: 1.5em;