diff --git a/e2e/web-ui-sweep/profiles-scope.spec.ts b/e2e/web-ui-sweep/profiles-scope.spec.ts index 3be3d6751..9797c93c1 100644 --- a/e2e/web-ui-sweep/profiles-scope.spec.ts +++ b/e2e/web-ui-sweep/profiles-scope.spec.ts @@ -226,7 +226,7 @@ test('5. A blocked call: attribution chips, Allow in profile… and Why?', async await expect(page.locator('[data-test^="activity-why-"]')).toBeFocused() }) -// 1280 is the first width that shows the Scope column; 768-1100 is where it used to clip Status and Duration. +// 1024 (lg) is the first width that shows the Scope column; the inline Why? needs 1280 (xl); 768-1100 is where it used to clip Status and Duration. for (const width of [1440, 1280, 1100, 1024, 900, 768, 390]) { test(`6. layout at ${width}px: no horizontal scroll, chips not clipped`, async ({ page }) => { await page.setViewportSize({ width, height: 900 }) @@ -301,8 +301,8 @@ for (const width of [1440, 1280, 1100, 1024, 900, 768, 390]) { const target = await why.boundingBox() expect(target!.width).toBeGreaterThanOrEqual(24) expect(target!.height).toBeGreaterThanOrEqual(24) - if (width < 1280) { - // Below xl the Scope column folds away (it widened the table past its card); the drawer carries the chips. + if (width < 1024) { + // Below lg the Scope column folds away (it widened the table past its card); the drawer carries the chips. await expect(page.locator('[data-test="activity-scope-col"]')).toBeHidden() await expect(page.locator('[data-test="activity-drawer-attribution"]')).toBeVisible() await expect(page.locator('[data-test="activity-drawer-attribution"] [data-test="attribution-client"]')).toBeVisible() diff --git a/frontend/src/views/Activity.vue b/frontend/src/views/Activity.vue index 95262a4f2..558c8614e 100644 --- a/frontend/src/views/Activity.vue +++ b/frontend/src/views/Activity.vue @@ -585,9 +585,9 @@ Server {{ getSortIndicator('server_name') }} - Scope + Scope Details Sensitive @@ -698,7 +698,7 @@ - - + @@ -862,7 +862,18 @@ > {{ statusPresentation(row.activity.status).label }} - + + {{ statusPresentation(row.activity.status).label }}
-

🔍 Search results ({{ filteredFields.length }})

+

Search results ({{ filteredFields.length }})

@@ -60,7 +60,7 @@
-

🔒 Security & Access

+

Security & Access

The settings that most affect how exposed and protected your instance is.

@@ -92,7 +92,7 @@
-

⚙️ General

+

General

diff --git a/frontend/src/views/settings/fields.ts b/frontend/src/views/settings/fields.ts index cb6d605e8..ad3ebe247 100644 --- a/frontend/src/views/settings/fields.ts +++ b/frontend/src/views/settings/fields.ts @@ -360,7 +360,7 @@ export const GENERAL_FIELDS: SettingField[] = [ // `teams` -> `server_edition` on load, and Settings.vue aliases it defensively // so old configs hydrate the form while edits always save under `server_edition`. export const SERVER_EDITION_TAB_LABEL = 'Server Edition' -export const SERVER_EDITION_SECTION_TITLE = '👥 Server Edition' +export const SERVER_EDITION_SECTION_TITLE = 'Server Edition' // // Spec 107 PR-B (T054): this row set is asserted EXACTLY by // `tests/unit/settings-server-edition-wording.spec.ts`. The `Settings` diff --git a/frontend/tests/unit/activity-table-scanning.spec.ts b/frontend/tests/unit/activity-table-scanning.spec.ts index 241f10f7a..58b6e0af2 100644 --- a/frontend/tests/unit/activity-table-scanning.spec.ts +++ b/frontend/tests/unit/activity-table-scanning.spec.ts @@ -161,6 +161,8 @@ describe('Activity table — only failures are marked (F5)', () => { expect(successCell.text()).toBe('Success') // sr-only: present in the accessibility tree, absent from the scan. expect(successCell.classes()).toContain('sr-only') + // I8a: a visible check icon with a Success title accompanies it. + expect(rows(wrapper)[0].find('[data-test="activity-status-icon"] title').text()).toBe('Success') const errorCell = rows(wrapper) .find(r => r.text().includes('Error'))! diff --git a/frontend/tests/unit/clients-page.spec.ts b/frontend/tests/unit/clients-page.spec.ts index 789c3819f..32126561e 100644 --- a/frontend/tests/unit/clients-page.spec.ts +++ b/frontend/tests/unit/clients-page.spec.ts @@ -87,6 +87,27 @@ describe('Clients page', () => { expect(wrapper.find('a[href="/usage?client=cursor"]').exists()).toBe(true) }) + it('exposes a keyboard-operable expander button whose aria-expanded flips (I7)', async () => { + const router = makeRouter() + await router.push('/clients') + await router.isReady() + const wrapper = mount(Clients, { + global: { plugins: [router], stubs: { ClientConnectList: true, AgentTokens: true, ModeSwitcher: true } }, + }) + await flushPromises() + const btn = wrapper.find('[data-test="client-expand-cursor"]') + expect(btn.element.tagName).toBe('BUTTON') + expect(btn.attributes('aria-expanded')).toBe('false') + expect(btn.attributes('aria-label')).toContain('Show details for') + await btn.trigger('click') + await flushPromises() + expect(btn.attributes('aria-expanded')).toBe('true') + expect(api.getClient).toHaveBeenCalledTimes(1) + await btn.trigger('click') + await flushPromises() + expect(btn.attributes('aria-expanded')).toBe('false') + }) + it('reads the tab from the URL and preserves unrelated query parameters when changing tabs', async () => { const router = makeRouter() await router.push('/clients?tab=endpoint&token=agent-1') diff --git a/frontend/tests/unit/server-detail-quarantine-tools-empty.spec.ts b/frontend/tests/unit/server-detail-quarantine-tools-empty.spec.ts index bea59b01b..ac2685dde 100644 --- a/frontend/tests/unit/server-detail-quarantine-tools-empty.spec.ts +++ b/frontend/tests/unit/server-detail-quarantine-tools-empty.spec.ts @@ -77,6 +77,10 @@ const quarantined = (extra: ServerOverrides = {}): ServerOverrides => ({ ...extra, }) +function empty_text(w: any): string { + return w.find('[data-test="server-tools-empty"]').text() +} + describe('ServerDetail — Tools tab empty state on a quarantined server (F08)', () => { beforeEach(() => { setActivePinia(createPinia()) @@ -131,15 +135,16 @@ describe('ServerDetail — Tools tab empty state on a quarantined server (F08)', expect(text).not.toMatch(/\d/) }) - it('offers a way through to the Security tab where the findings live', async () => { + it('offers a way through to the Review tab', async () => { const wrapper = await mountDetail( quarantined({ quarantine: { pending_count: 2, changed_count: 0, blocked_count: 0 } }) ) const cta = wrapper.find('[data-test="server-tools-empty-security"]') expect(cta.exists()).toBe(true) + expect(empty_text(wrapper)).not.toContain('Security tab') await cta.trigger('click') await flushPromises() - expect(wrapper.find('[data-test="security-tab"]').classes()).toContain('tab-active') + expect(wrapper.find('[data-test="review-tab"]').classes()).toContain('tab-active') }) // Integrated-review finding. The withheld copy told the user to "approve the