From 85f193faff182b26b53a51ee70267d3ed22a254d Mon Sep 17 00:00:00 2001 From: pengmin Date: Tue, 1 Sep 2026 16:55:18 +0800 Subject: [PATCH 1/2] fix(ui): send collection intervals as numbers Convert collection source update intervals at the API boundary so numeric form input is serialized as a JSON number. Constrain the form to the backend's minute-based integer contract and cover the request body with a focused Playwright regression test.\n\nAssisted-by: Codex:gpt-5 [eslint] Signed-off-by: pengmin --- core/http/react-ui/e2e/collections.spec.js | 29 +++++++++++++++++++ .../react-ui/src/pages/CollectionDetails.jsx | 6 ++-- core/http/react-ui/src/utils/api.js | 5 +++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/core/http/react-ui/e2e/collections.spec.js b/core/http/react-ui/e2e/collections.spec.js index 4fa4168dde94..f3f4bd8c291e 100644 --- a/core/http/react-ui/e2e/collections.spec.js +++ b/core/http/react-ui/e2e/collections.spec.js @@ -19,4 +19,33 @@ test.describe('Collections page', () => { await input.fill('my-kb') await expect(input).toHaveValue('my-kb') }) + + test('posts the source update interval as a JSON number', async ({ page }) => { + const collectionName = 'interval-regression' + const collectionPath = encodeURIComponent(collectionName) + let postedBody + + await page.route(`**/api/agents/collections/${collectionPath}/entries`, route => + route.fulfill({ contentType: 'application/json', body: JSON.stringify({ entries: [] }) })) + await page.route(`**/api/agents/collections/${collectionPath}/sources`, async route => { + if (route.request().method() === 'POST') { + postedBody = route.request().postDataJSON() + await route.fulfill({ contentType: 'application/json', body: JSON.stringify({ status: 'ok' }) }) + } else { + await route.fulfill({ contentType: 'application/json', body: JSON.stringify({ sources: [] }) }) + } + }) + + await page.goto(`/app/collections/${collectionPath}`) + await page.getByRole('button', { name: 'Sources' }).click() + await page.locator('#source-url').fill('https://example.com/feed') + await page.locator('#source-interval').fill('3600') + await page.getByRole('button', { name: 'Add Source' }).click() + + await expect.poll(() => postedBody).toEqual({ + url: 'https://example.com/feed', + update_interval: 3600, + }) + expect(typeof postedBody.update_interval).toBe('number') + }) }) diff --git a/core/http/react-ui/src/pages/CollectionDetails.jsx b/core/http/react-ui/src/pages/CollectionDetails.jsx index 0469df0781b8..2ce4b699109f 100644 --- a/core/http/react-ui/src/pages/CollectionDetails.jsx +++ b/core/http/react-ui/src/pages/CollectionDetails.jsx @@ -432,10 +432,12 @@ export default function CollectionDetails() { setNewSourceInterval(e.target.value)} - placeholder="e.g. 1h, 30m" + placeholder="e.g. 60 (minutes)" />