From eeade9c19fcdaea380e1fdb2fd4fab89fb1cf37a Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:38:50 +0800 Subject: [PATCH] fix(knowledge_fs): allow updating external access before profile activation --- .../knowledge-settings-form.spec.tsx | 71 ++++++++++++++++++- .../new-rag/knowledge-settings-form.tsx | 3 +- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/web/features/new-rag/__tests__/knowledge-settings-form.spec.tsx b/web/features/new-rag/__tests__/knowledge-settings-form.spec.tsx index 2c2a4bb4cfc..71b9e0f2ece 100644 --- a/web/features/new-rag/__tests__/knowledge-settings-form.spec.tsx +++ b/web/features/new-rag/__tests__/knowledge-settings-form.spec.tsx @@ -627,6 +627,73 @@ describe('KnowledgeSettingsForm', () => { expect(toastMock.success).not.toHaveBeenCalled() }) + it('keeps access channels submittable before the first model profile activates', async () => { + const user = userEvent.setup() + renderForm({ + settings: { + ...settings, + active_profile_available: false, + active_profile_revisions: {}, + capabilities: { + deep: false, + index: false, + ingest: true, + query: false, + research: false, + source_sync: true, + }, + }, + }) + + const apiAccessSwitch = screen.getByRole('switch', { + name: 'dataset.newKnowledge.apiAgentAccess', + }) + const workflowAccessSwitch = screen.getByRole('switch', { + name: 'dataset.newKnowledge.workflowAccess', + }) + expect(apiAccessSwitch).not.toHaveAttribute('aria-disabled', 'true') + expect(workflowAccessSwitch).not.toHaveAttribute('aria-disabled', 'true') + expect(apiAccessSwitch).toHaveAccessibleDescription( + 'dataset.newKnowledge.settings.apiAccessDescription', + ) + + await user.click(apiAccessSwitch) + + await waitFor(() => { + expect(serviceMock.patchExternalAccess).toHaveBeenCalledWith( + { + body: { + agent_enabled: false, + mcp_enabled: true, + service_api_enabled: false, + workflow_enabled: true, + }, + params: { control_space_id: 'space-1' }, + }, + expect.anything(), + ) + }) + await waitFor(() => expect(apiAccessSwitch).toHaveAttribute('aria-checked', 'false')) + expect(apiAccessSwitch).not.toHaveAttribute('aria-disabled', 'true') + expect(workflowAccessSwitch).not.toHaveAttribute('aria-disabled', 'true') + + await user.click(apiAccessSwitch) + + await waitFor(() => expect(serviceMock.patchExternalAccess).toHaveBeenCalledTimes(2)) + expect(serviceMock.patchExternalAccess).toHaveBeenLastCalledWith( + { + body: { + agent_enabled: true, + mcp_enabled: true, + service_api_enabled: true, + workflow_enabled: true, + }, + params: { control_space_id: 'space-1' }, + }, + expect.anything(), + ) + }) + it('keeps unrelated form controls interactive while external access is saving', async () => { const user = userEvent.setup() let finishExternalAccessSave!: (value: typeof externalAccess) => void @@ -1558,10 +1625,10 @@ describe('KnowledgeSettingsForm', () => { ) expect( screen.getByRole('switch', { name: 'dataset.newKnowledge.apiAgentAccess' }), - ).toHaveAttribute('aria-disabled', 'true') + ).not.toHaveAttribute('aria-disabled', 'true') expect( screen.getByRole('switch', { name: 'dataset.newKnowledge.workflowAccess' }), - ).toHaveAttribute('aria-disabled', 'true') + ).not.toHaveAttribute('aria-disabled', 'true') await user.click( screen.getByRole('button', { diff --git a/web/features/new-rag/knowledge-settings-form.tsx b/web/features/new-rag/knowledge-settings-form.tsx index 4a3fd1f8858..dd647c36fc1 100644 --- a/web/features/new-rag/knowledge-settings-form.tsx +++ b/web/features/new-rag/knowledge-settings-form.tsx @@ -366,7 +366,6 @@ export function KnowledgeSettingsForm({ const canManageAccess = space.permission_keys.includes('knowledge_space_access_config') const canDelete = space.permission_keys.includes('knowledge_space_delete') const initialModelSetup = !settings.active_profile_available - const modelSetupReady = settings.active_profile_available const readinessFieldLabel = (field: KnowledgeFsSettingsResponse['issues'][number]['field']) => { if (field === 'embedding') return tSettings(($) => $['form.embeddingModel']) if (field === 'reasoning') return tCommon(($) => $['modelProvider.systemReasoningModel.key']) @@ -451,7 +450,7 @@ export function KnowledgeSettingsForm({ settingsMutation.isPending || Boolean(pendingMigrationId) const basicFieldsDisabled = !canEdit || isBasicSaving - const externalAccessDisabled = !canEdit || !canManageAccess || !modelSetupReady + const externalAccessDisabled = !canEdit || !canManageAccess const retrievalFieldsDisabled = !canEdit || (!initialModelSetup && embeddingDirty) const saveDisabled = !basicDirty ||