From f5aba417edd49cb9ff32cc6c1bd41374193ed4cc Mon Sep 17 00:00:00 2001 From: xarmian Date: Sun, 11 Oct 2026 16:22:44 +0000 Subject: [PATCH] feat(web): the mobile view sheet lists saved views and "All" (TASK-3589) On a phone, the "Choose view" sheet offered only List, Board and Table. Saved views and "All" were only in the desktop menu, so a saved workflow disappeared at phone width. The sheet now lists them under "Saved views", using the same handlers as the desktop menu, and marks the default with its pin. Managing views (save, delete, set default) stays desktop-only. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ --- web/e2e/task-3589-mobile-saved-views.spec.ts | 49 +++++++++++++++++++ web/src/lib/eachKeyCensus.ts | 1 + .../[workspace]/[collection]/+page.svelte | 42 ++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 web/e2e/task-3589-mobile-saved-views.spec.ts 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;