Open a team's shared source on the Knowledge page

Also cover the owner-only API write allowlist in the agent details modal.
This commit is contained in:
arc53-machine committed 2026-09-29 14:12:35 +01:00
1 parent ca6f840fcd
commit a777aeac45
3 files changed
+60 -4

No files matched your search

+32 -2
View File
@@ -17,8 +17,11 @@ vi.mock('react-redux', () => ({
}));
vi.mock('../api/services/userService', () => ({ default: mocks }));
// Tested on its own; it needs the store and the tool list.
vi.mock('../agents/ApiWriteAllowlist', () => ({ default: () => null }));
// Tested on its own; it needs the store and the tool list. Here it only has
// to show up (or not).
vi.mock('../agents/ApiWriteAllowlist', () => ({
default: () => <div data-testid="api-write-allowlist" />,
}));
vi.mock('./ConfirmationModal', () => ({
default: ({
@@ -99,6 +102,33 @@ describe('AgentDetailsModal', () => {
);
});
// The allowlist acts on the owner's connected accounts; the server keeps
// it unchanged for anyone else, so only the owner sees it.
describe('API write allowlist', () => {
const allowlist = () =>
document.querySelector('[data-testid="api-write-allowlist"]');
it('shows it to the owner of an agent with a key', async () => {
await render({ status: 'published', key: 'k-1', access: 'owner' });
expect(allowlist()).not.toBeNull();
});
it('hides it from an editor, even with a key', async () => {
await render({
status: 'published',
key: 'k-1',
access: 'editor',
allowed_actions: ['view', 'edit', 'manage_access_details'],
});
expect(allowlist()).toBeNull();
});
it('hides it until the agent has a key', async () => {
await render({ status: 'published', access: 'owner' });
expect(allowlist()).toBeNull();
});
});
it('shows a refused public link in an alert', async () => {
mocks.shareAgent.mockReturnValue(
respond({ success: false, message: 'Not allowed' }, false),
+27 -1
View File
@@ -1,6 +1,6 @@
import { act } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { MemoryRouter } from 'react-router-dom';
import { MemoryRouter, useLocation } from 'react-router-dom';
// A JWT whose payload is {"sub":"me"}.
const TOKEN = `x.${btoa(JSON.stringify({ sub: 'me' }))}.y`;
@@ -183,6 +183,10 @@ describe('Teams page', () => {
document.body.innerHTML = '';
});
function Where() {
return <div data-testid="where">{useLocation().pathname}</div>;
}
const render = async () => {
act(() => {
root.render(
@@ -190,6 +194,7 @@ describe('Teams page', () => {
initialEntries={[{ pathname: '/teams', state: { openTeamId: 't1' } }]}
>
<Teams />
<Where />
</MemoryRouter>,
);
});
@@ -362,6 +367,27 @@ describe('Teams page', () => {
);
});
it('opens a shared source on the Knowledge page', async () => {
listGrants.mockResolvedValue({
team_role: 'team_member',
grants: [grant({ caller: VIEWER })],
});
await render();
await openDrawer();
const open = Array.from(
body().querySelectorAll<HTMLButtonElement>(
'[data-slot="sheet-content"] button',
),
).find((b) =>
b.textContent?.startsWith('settings.teams.drawer.open(type='),
)!;
act(() => open.click());
await flush();
expect(body().querySelector('[data-testid="where"]')?.textContent).toBe(
'/settings/knowledge',
);
});
it('sends target_user_id when removing a per-member grant', async () => {
listGrants.mockResolvedValue({
team_role: 'team_admin',
+1 -1
View File
@@ -737,7 +737,7 @@ export default function Teams() {
return agent ? agentEditPathFor(agent) : agentEditPath(r.id);
}
case 'source':
return '/settings/sources';
return '/settings/knowledge';
case 'tool':
return '/settings/tools';
case 'prompt':