-
+
+
-
{fileName}
-
+
{fileName}
+
{data?.mimeType ?? localize('com_ui_unknown_file_type')}
diff --git a/eslint-suppressions.json b/eslint-suppressions.json
index 5b5892571cc..4476c66c82c 100644
--- a/eslint-suppressions.json
+++ b/eslint-suppressions.json
@@ -1730,11 +1730,8 @@
}
},
"client/src/components/SidePanel/Agents/Tools/CategoryFilter.tsx": {
- "shadcn/no-raw-colors": {
- "count": 1
- },
"shadcn/no-restyle": {
- "count": 6
+ "count": 4
}
},
"client/src/components/SidePanel/Agents/Tools/ItemDialog/ItemDialog.tsx": {
@@ -2086,9 +2083,6 @@
"shadcn/no-arbitrary-values": {
"count": 3
},
- "shadcn/no-raw-colors": {
- "count": 1
- },
"shadcn/no-restyle": {
"count": 5
}
diff --git a/packages/client/src/theme/allowlist.md b/packages/client/src/theme/allowlist.md
index 6eaf706be4d..53155448f3d 100644
--- a/packages/client/src/theme/allowlist.md
+++ b/packages/client/src/theme/allowlist.md
@@ -51,3 +51,10 @@ is a role, not an exception.
| `client/src/utils/mermaid.ts` | The mermaid artifact document and its zoom controls render in a sandboxed iframe without theme variables; the token reads' fallbacks and the luminance repair ink are literals by necessity. |
| `client/src/utils/richtext.ts` | Inline styles on HTML copied to the clipboard for pasting into other apps, which must not carry the sender's theme. |
| `client/src/utils/officePreview.ts`, `client/src/hooks/ScreenshotContext.tsx` | Fallbacks for a theme role read at runtime, used only when the variable is unset. |
+
+## Panels: media and third-party surfaces
+
+| File | Why |
+| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
+| `client/src/components/Nav/SettingsTabs/Account/Avatar.tsx` | The move hint drawn over the user's photo in the avatar cropper: a media scrim with white ink, independent of the theme around the image. |
+| `client/src/hooks/Files/useSharePointPicker.ts` | Background of Microsoft's SharePoint file picker iframe, matched to that third party's own surface. |
From 508db29542783ae010d50e3345f00e58f78fa047 Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Tue, 29 Sep 2026 08:27:24 +0200
Subject: [PATCH 2/3] test: Cover the Skills Category Filter's Active State
---
.../scenarios/category-filter-state.spec.ts | 74 +++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 e2e/specs/mock/scenarios/category-filter-state.spec.ts
diff --git a/e2e/specs/mock/scenarios/category-filter-state.spec.ts b/e2e/specs/mock/scenarios/category-filter-state.spec.ts
new file mode 100644
index 00000000000..4e76770d361
--- /dev/null
+++ b/e2e/specs/mock/scenarios/category-filter-state.spec.ts
@@ -0,0 +1,74 @@
+import { expect, test } from '@playwright/test';
+import type { Locator, Page } from '@playwright/test';
+import { openAgentBuilder } from '../agents.helpers';
+import { getAccessToken, requestJson } from '../helpers';
+
+/**
+ * Picking a category in the Skills dialog marks the filter as active on its icon, drawn in the
+ * theme's accent role; the resting filter keeps the tertiary icon. The state used to be a raw
+ * emerald border no theme could set.
+ */
+type SkillSummary = { _id: string; name: string };
+
+async function resolveRole(page: Page, role: string): Promise
{
+ return page.evaluate((name) => {
+ const probe = document.createElement('div');
+ probe.style.color = `rgb(var(--${name}))`;
+ document.body.appendChild(probe);
+ const color = getComputedStyle(probe).color;
+ probe.remove();
+ return color;
+ }, role);
+}
+
+async function openSkillsPicker(page: Page): Promise {
+ const form = await openAgentBuilder(page);
+ await form.getByRole('radio', { name: 'Selected', exact: true }).click();
+ const addSkill = form.getByRole('button', { name: /Add skill/ }).first();
+ await expect(addSkill).toBeVisible();
+ await addSkill.click();
+ const dialog = page.getByRole('dialog', { name: 'Skills', exact: true });
+ await expect(dialog).toBeVisible();
+ return dialog;
+}
+
+const filterIconColor = (trigger: Locator) =>
+ trigger
+ .locator('svg')
+ .first()
+ .evaluate((icon) => getComputedStyle(icon).color);
+
+test('an active skills category shows on the filter icon in the accent role @scenario:skills-category-filter-shows-active-state', async ({
+ page,
+}) => {
+ test.setTimeout(120_000);
+ await page.goto('/c/new', { timeout: 15_000 });
+ const token = await getAccessToken(page);
+ const suffix = `${Date.now().toString(36)}-${Math.floor(Math.random() * 1e4)}`;
+ const category = `theme-${suffix}`;
+ const skill = await requestJson(page, {
+ path: '/api/skills',
+ token,
+ method: 'POST',
+ body: {
+ name: `category-filter-${suffix}`,
+ description: 'Carries a category so the Skills dialog offers a category filter.',
+ body: '# Category filter\n\nUsed by the category filter end-to-end test.',
+ category,
+ },
+ });
+
+ try {
+ const dialog = await openSkillsPicker(page);
+ const trigger = dialog.getByRole('button', { name: 'Category' });
+ await expect(trigger).toBeVisible();
+ expect(await filterIconColor(trigger)).toBe(await resolveRole(page, 'text-tertiary'));
+
+ await trigger.click();
+ await page.getByRole('menuitem', { name: category }).click();
+ await expect(trigger).toContainText(category);
+ expect(await filterIconColor(trigger)).toBe(await resolveRole(page, 'accent-primary'));
+ } finally {
+ await requestJson(page, { path: `/api/skills/${skill._id}`, token, method: 'DELETE' });
+ }
+});
From 890a477fbad8b9d05f563788462ec214242c186d Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Tue, 29 Sep 2026 08:49:27 +0200
Subject: [PATCH 3/3] test: Match the Category Filter Trigger Exactly
---
e2e/specs/mock/scenarios/category-filter-state.spec.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/e2e/specs/mock/scenarios/category-filter-state.spec.ts b/e2e/specs/mock/scenarios/category-filter-state.spec.ts
index 4e76770d361..f9fa4a96435 100644
--- a/e2e/specs/mock/scenarios/category-filter-state.spec.ts
+++ b/e2e/specs/mock/scenarios/category-filter-state.spec.ts
@@ -51,7 +51,7 @@ test('an active skills category shows on the filter icon in the accent role @sce
token,
method: 'POST',
body: {
- name: `category-filter-${suffix}`,
+ name: `filter-state-${suffix}`,
description: 'Carries a category so the Skills dialog offers a category filter.',
body: '# Category filter\n\nUsed by the category filter end-to-end test.',
category,
@@ -60,7 +60,7 @@ test('an active skills category shows on the filter icon in the accent role @sce
try {
const dialog = await openSkillsPicker(page);
- const trigger = dialog.getByRole('button', { name: 'Category' });
+ const trigger = dialog.getByRole('button', { name: 'Category', exact: true });
await expect(trigger).toBeVisible();
expect(await filterIconColor(trigger)).toBe(await resolveRole(page, 'text-tertiary'));