feat: replace Today workspace surface with Overview
This commit is contained in:
@@ -52,7 +52,7 @@ test.describe('Command Palette', () => {
|
||||
const palette = page.locator('.command-palette');
|
||||
await expect(palette).toBeVisible();
|
||||
const items = palette.locator('.command-palette-item');
|
||||
await expect(items.nth(0)).toHaveAttribute('data-command-id', 'verstak.shell.open-today');
|
||||
await expect(items.nth(0)).toHaveAttribute('data-command-id', 'verstak.shell.open-overview');
|
||||
await expect(items.nth(1)).toHaveAttribute('data-command-id', 'verstak.shell.open-files');
|
||||
await expect(items.nth(2)).toHaveAttribute('data-command-id', 'verstak.shell.open-activity');
|
||||
await expect(items.nth(3)).toHaveAttribute('data-command-id', 'verstak.shell.open-browser-inbox');
|
||||
|
||||
@@ -99,19 +99,19 @@ test.describe('E: Plugin Manager layout', () => {
|
||||
await expect(selected).toHaveText('Test');
|
||||
});
|
||||
|
||||
test('workspace tools render Today first with Files as one tab', async ({ page }) => {
|
||||
test('workspace tools render Overview first with Files as one tab', async ({ page }) => {
|
||||
await page.locator('.wt-label').filter({ hasText: 'Project' }).click();
|
||||
|
||||
const tabs = page.locator('.workspace-tabs');
|
||||
await expect(tabs).toBeVisible({ timeout: 10000 });
|
||||
const todayTab = tabs.locator('[role="tab"]').filter({ hasText: 'Today' });
|
||||
const overviewTab = tabs.locator('[role="tab"]').filter({ hasText: 'Overview' });
|
||||
const filesTab = tabs.locator('[role="tab"]').filter({ hasText: 'Files' });
|
||||
await expect(todayTab).toBeVisible();
|
||||
await expect(todayTab).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(overviewTab).toBeVisible();
|
||||
await expect(overviewTab).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(filesTab).toBeVisible();
|
||||
await expect(filesTab).toHaveAttribute('aria-selected', 'false');
|
||||
await expect(page.locator('.workspace-tool')).toHaveCount(0);
|
||||
await expect(page.locator('.today-root')).toBeVisible();
|
||||
await expect(page.locator('[data-overview-root]')).toBeVisible();
|
||||
|
||||
await filesTab.click();
|
||||
await expect(page.locator('.files-root')).toBeVisible();
|
||||
|
||||
@@ -99,7 +99,7 @@ test.describe('UX follow-up fixes', () => {
|
||||
expect(workspaceBox.width).toBeGreaterThan(340);
|
||||
expect(workspaceBox.y).toBeGreaterThan(sidebarBox.y + sidebarBox.height - 1);
|
||||
await expect(page.locator('.workspace-header [data-global-search-input]')).toBeVisible();
|
||||
await expect(page.getByRole('tab', { name: 'Today' })).toBeVisible();
|
||||
await expect(page.getByRole('tab', { name: 'Overview' })).toBeVisible();
|
||||
|
||||
const hasHorizontalOverflow = await page.evaluate(() => document.documentElement.scrollWidth > window.innerWidth);
|
||||
expect(hasHorizontalOverflow).toBe(false);
|
||||
|
||||
+103
-33
@@ -1,7 +1,7 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { waitForAppReady, setupConsoleCollector, resetMockState } from './helpers.js';
|
||||
|
||||
test.describe('UX Today workspace flow', () => {
|
||||
test.describe('UX Overview workspace flow', () => {
|
||||
let consoleCollector;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@@ -15,37 +15,40 @@ test.describe('UX Today workspace flow', () => {
|
||||
consoleCollector.assertNoErrors();
|
||||
});
|
||||
|
||||
test('workspace opens with Today before plugin tools', async ({ page }) => {
|
||||
test('workspace opens with Overview before plugin tools', async ({ page }) => {
|
||||
await expect(page.locator('.workspace-host')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
const tabs = page.getByRole('tab');
|
||||
await expect(tabs.nth(0)).toHaveText('Today');
|
||||
await expect(tabs.nth(0)).toHaveText('Overview');
|
||||
await expect(tabs.nth(1)).toHaveText('Files');
|
||||
await expect(page.getByRole('tab', { name: 'Today' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.getByRole('tab', { name: 'Overview' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.getByRole('tab', { name: 'Today' })).toHaveCount(0);
|
||||
|
||||
const today = page.locator('.today-root');
|
||||
await expect(today).toBeVisible();
|
||||
await expect(today.locator('[data-today-section="captured"]')).toContainText('Captured');
|
||||
await expect(today.locator('[data-today-section="activity"]')).toContainText('Recent Activity');
|
||||
await expect(today.locator('[data-today-section="worklog"]')).toContainText('Worklog Suggestions');
|
||||
await expect(today.locator('[data-today-section="quick-actions"]')).toContainText('Quick Actions');
|
||||
await expect(today).toContainText('No browser captures yet');
|
||||
await expect(today).toContainText('No activity events yet');
|
||||
const overview = page.locator('[data-overview-root]');
|
||||
await expect(overview).toBeVisible();
|
||||
await expect(overview.locator('[data-overview-section="continue"]')).toContainText('Continue working');
|
||||
await expect(overview.locator('[data-overview-section="recent"]')).toContainText('Recent changes');
|
||||
await expect(overview.locator('[data-overview-section="attention"]')).toContainText('Needs attention');
|
||||
await expect(overview.locator('[data-overview-section="quick-actions"]')).toContainText('Quick actions');
|
||||
await expect(overview.locator('[data-overview-summary="notes"]')).toContainText('recent changes');
|
||||
await expect(overview.locator('[data-overview-summary="captures"]')).toContainText('unprocessed captures');
|
||||
await expect(overview).toContainText('No clear resume point yet');
|
||||
await expect(overview).toContainText('No meaningful changes for this filter yet');
|
||||
});
|
||||
|
||||
test('Today quick action opens Browser Inbox workspace tool', async ({ page }) => {
|
||||
await page.locator('[data-today-action="browser-inbox"]').click();
|
||||
test('Overview quick action opens Browser Inbox workspace tool', async ({ page }) => {
|
||||
await page.locator('[data-overview-action="browser-inbox"]').click();
|
||||
|
||||
await expect(page.getByRole('tab', { name: 'Browser Inbox' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.locator('.browser-inbox-root')).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Today summarizes available work and highlights the next resume item', async ({ page }) => {
|
||||
test('Overview prioritizes resume work and filters meaningful recent changes', async ({ page }) => {
|
||||
await page.evaluate(async () => {
|
||||
await window.go.api.App.WritePluginSettings('verstak.browser-inbox', {
|
||||
'captures:workspace:Project': [
|
||||
{
|
||||
captureId: 'today-capture-1',
|
||||
captureId: 'overview-capture-1',
|
||||
capturedAt: '2026-06-30T08:00:00.000Z',
|
||||
kind: 'page',
|
||||
url: 'https://example.com/research',
|
||||
@@ -54,7 +57,7 @@ test.describe('UX Today workspace flow', () => {
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
{
|
||||
captureId: 'today-capture-2',
|
||||
captureId: 'overview-capture-2',
|
||||
capturedAt: '2026-06-30T08:15:00.000Z',
|
||||
kind: 'selection',
|
||||
title: 'Quote to process',
|
||||
@@ -66,41 +69,108 @@ test.describe('UX Today workspace flow', () => {
|
||||
await window.go.api.App.WritePluginSettings('verstak.activity', {
|
||||
'events:workspace:Project': [
|
||||
{
|
||||
activityId: 'today-activity-1',
|
||||
activityId: 'overview-selected-file',
|
||||
occurredAt: '2026-06-30T08:50:00.000Z',
|
||||
type: 'file.selected',
|
||||
title: 'Selected file',
|
||||
summary: 'Project/draft.md',
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
{
|
||||
activityId: 'overview-opened-file',
|
||||
occurredAt: '2026-06-30T08:40:00.000Z',
|
||||
type: 'file.opened',
|
||||
title: 'draft.md',
|
||||
summary: 'Project/draft.md',
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
{
|
||||
activityId: 'overview-note',
|
||||
occurredAt: '2026-06-30T08:25:00.000Z',
|
||||
type: 'note.saved',
|
||||
title: 'Saved research note',
|
||||
summary: 'Project/Notes/Research.md',
|
||||
title: 'Overview',
|
||||
summary: 'Project/Notes/Overview.md',
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
{
|
||||
activityId: 'overview-file',
|
||||
occurredAt: '2026-06-30T08:20:00.000Z',
|
||||
type: 'file.changed',
|
||||
title: 'draft.md',
|
||||
summary: 'Project/draft.md',
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
{
|
||||
activityId: 'overview-workspace-selected',
|
||||
occurredAt: '2026-06-30T08:10:00.000Z',
|
||||
type: 'case.selected',
|
||||
title: 'Workspace selected',
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
],
|
||||
});
|
||||
await window.go.api.App.WritePluginSettings('verstak.journal', {
|
||||
'suggestions:workspace:Project': [
|
||||
'worklog:workspace:Project': [
|
||||
{
|
||||
entryId: 'today-worklog-1',
|
||||
entryId: 'overview-journal-1',
|
||||
date: '2026-06-30',
|
||||
title: 'Write project summary',
|
||||
summary: 'Turn recent captures into a worklog entry',
|
||||
minutes: 35,
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
],
|
||||
'suggestions:workspace:Project': [
|
||||
{
|
||||
suggestionId: 'overview-suggestion-1',
|
||||
date: '2026-06-30',
|
||||
title: 'Project work on 2026-06-30',
|
||||
minutes: 50,
|
||||
workspaceRootPath: 'Project',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
await page.locator('.today-header').getByRole('button', { name: 'Refresh' }).click();
|
||||
await page.locator('[data-overview-action="refresh"]').click();
|
||||
|
||||
const today = page.locator('.today-root');
|
||||
await expect(today.locator('[data-today-summary="captures"]')).toContainText('2');
|
||||
await expect(today.locator('[data-today-summary="activity"]')).toContainText('1');
|
||||
await expect(today.locator('[data-today-summary="worklog"]')).toContainText('1');
|
||||
const overview = page.locator('[data-overview-root]');
|
||||
await expect(overview.locator('[data-overview-summary="notes"]')).toContainText('1');
|
||||
await expect(overview.locator('[data-overview-summary="files"]')).toContainText('1');
|
||||
await expect(overview.locator('[data-overview-summary="captures"]')).toContainText('2');
|
||||
await expect(overview.locator('[data-overview-summary="journal"]')).toContainText('1');
|
||||
await expect(overview.locator('[data-overview-summary="attention"]')).toContainText('3');
|
||||
|
||||
const resume = today.locator('[data-today-section="resume"]');
|
||||
await expect(resume).toContainText('Resume next');
|
||||
await expect(resume).toContainText('Research Report');
|
||||
await resume.locator('[data-today-action="resume-primary"]').click();
|
||||
const resume = overview.locator('[data-overview-section="continue"]');
|
||||
await expect(resume).toContainText('Opened file "draft.md"');
|
||||
await expect(resume).not.toContainText('Research Report');
|
||||
await resume.locator('[data-overview-action="continue-primary"]').click();
|
||||
|
||||
await expect(page.getByRole('tab', { name: 'Browser Inbox' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.locator('.browser-inbox-root')).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByRole('tab', { name: 'Files' })).toHaveAttribute('aria-selected', 'true');
|
||||
await expect(page.locator('.files-root')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
await page.getByRole('tab', { name: 'Overview' }).click();
|
||||
const recent = overview.locator('[data-overview-section="recent"]');
|
||||
await expect(recent).toContainText('Edited note "Overview"');
|
||||
await expect(recent).toContainText('Changed file "draft.md"');
|
||||
await expect(recent).toContainText('Captured page "Research Report"');
|
||||
await expect(recent).toContainText('Added journal entry "Write project summary"');
|
||||
await expect(recent).not.toContainText('Selected file');
|
||||
await expect(recent).not.toContainText('Workspace selected');
|
||||
await expect(recent).not.toContainText('file.opened');
|
||||
|
||||
await overview.locator('[data-overview-filter="notes"]').click();
|
||||
await expect(recent).toContainText('Edited note "Overview"');
|
||||
await expect(recent).not.toContainText('Changed file "draft.md"');
|
||||
await expect(recent).not.toContainText('Research Report');
|
||||
|
||||
await overview.locator('[data-overview-filter="captures"]').click();
|
||||
await expect(recent).toContainText('Captured page "Research Report"');
|
||||
await expect(recent).toContainText('Captured selection "Quote to process"');
|
||||
await expect(recent).not.toContainText('Edited note "Overview"');
|
||||
|
||||
await overview.locator('[data-overview-filter="journal"]').click();
|
||||
await expect(recent).toContainText('Added journal entry "Write project summary"');
|
||||
await expect(recent).not.toContainText('Changed file "draft.md"');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user