From fb7cf8cd073ce03354ec688c38da1b6d189bea7f Mon Sep 17 00:00:00 2001 From: Tharanidk Date: Thu, 16 Jul 2026 14:08:52 +0530 Subject: [PATCH 1/3] Allow enabling/disabling for custom templates --- platform-api/internal/service/llm.go | 8 ----- .../service/llm_provider_template_test.go | 33 +++++++++++++++---- .../ProviderTemplateOverview.tsx | 26 +++++++-------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/platform-api/internal/service/llm.go b/platform-api/internal/service/llm.go index fdcb5ebc5..89028e3ae 100644 --- a/platform-api/internal/service/llm.go +++ b/platform-api/internal/service/llm.go @@ -696,14 +696,6 @@ func (s *LLMProviderTemplateService) SetVersionEnabled(orgUUID, groupID, version if target == nil { return nil, apperror.LLMProviderTemplateNotFound.New() } - // Enable/disable is reserved for built-in ('wso2') templates only. Custom - // templates are managed via update/delete and cannot be toggled. - if target.ManagedBy != constants.PolicyManagedByWSO2 { - return nil, apperror.LLMProviderTemplateNotToggleable.New() - } - if err := ensureOriginMutable(target.Origin); err != nil { - return nil, err - } if !enabled { inUse, err := s.repo.CountProvidersUsingTemplate(groupID, orgUUID, v) if err != nil { diff --git a/platform-api/internal/service/llm_provider_template_test.go b/platform-api/internal/service/llm_provider_template_test.go index b127b5ee0..e6890010c 100644 --- a/platform-api/internal/service/llm_provider_template_test.go +++ b/platform-api/internal/service/llm_provider_template_test.go @@ -679,22 +679,41 @@ func TestLLMProviderTemplateServiceSetVersionEnabled_EnableIgnoresUsage(t *testi } } -func TestLLMProviderTemplateServiceSetVersionEnabled_RejectsCustomTemplate(t *testing.T) { +func TestLLMProviderTemplateServiceSetVersionEnabled_AllowsCustomTemplate(t *testing.T) { repo := &mockLLMProviderTemplateCRUDRepo{ + getByVersionFunc: func(templateID, orgUUID, version string) (*model.LLMProviderTemplate, error) { + return &model.LLMProviderTemplate{ID: templateID, Version: version, ManagedBy: "organization", Enabled: false}, nil + }, + } + svc := NewLLMProviderTemplateService(repo, &noopAuditRepo{}, newTestIdentityService()) + + resp, err := svc.SetVersionEnabled("org-1", "openai", "v2.0", false) + if err != nil { + t.Fatalf("expected custom template to be toggleable, got: %v", err) + } + if !repo.setEnabledCalled || repo.setEnabledEnabled { + t.Fatalf("expected SetEnabled to be called with enabled=false, got called=%v enabled=%v", repo.setEnabledCalled, repo.setEnabledEnabled) + } + if resp == nil || resp.Enabled == nil || *resp.Enabled { + t.Fatalf("expected response to reflect disabled state, got: %#v", resp) + } +} + +func TestLLMProviderTemplateServiceSetVersionEnabled_CustomTemplateDisableBlocksWhenInUse(t *testing.T) { + repo := &mockLLMProviderTemplateCRUDRepo{ + countProvidersUsingTemplateResult: 1, getByVersionFunc: func(templateID, orgUUID, version string) (*model.LLMProviderTemplate, error) { return &model.LLMProviderTemplate{ID: templateID, Version: version, ManagedBy: "organization"}, nil }, } svc := NewLLMProviderTemplateService(repo, &noopAuditRepo{}, newTestIdentityService()) - // Enable/disable is reserved for built-in ('wso2') templates; a custom - // ('organization') template must be rejected and never touch SetEnabled. _, err := svc.SetVersionEnabled("org-1", "openai", "v2.0", false) - if !apperror.LLMProviderTemplateNotToggleable.Is(err) { - t.Fatalf("expected ErrLLMProviderTemplateNotToggleable, got: %v", err) + if !apperror.LLMProviderTemplateInUse.Is(err) { + t.Fatalf("expected ErrLLMProviderTemplateInUse for in-use custom template, got: %v", err) } - if repo.setEnabledCalled || repo.countProvidersUsingTemplateCalled { - t.Fatalf("did not expect SetEnabled or usage check for a non-toggleable custom template") + if repo.setEnabledCalled { + t.Fatalf("did not expect SetEnabled to be called while version is in use") } } diff --git a/portals/ai-workspace/src/pages/appShell/appShellPages/providerTemplate/ProviderTemplateOverview.tsx b/portals/ai-workspace/src/pages/appShell/appShellPages/providerTemplate/ProviderTemplateOverview.tsx index 76be6aa08..ffb87dd22 100644 --- a/portals/ai-workspace/src/pages/appShell/appShellPages/providerTemplate/ProviderTemplateOverview.tsx +++ b/portals/ai-workspace/src/pages/appShell/appShellPages/providerTemplate/ProviderTemplateOverview.tsx @@ -841,19 +841,19 @@ export default function ProviderTemplateOverview() { /> )} - {isReadOnly && ( - - - {isEnabled ? 'Enabled' : 'Disabled'} - - void handleToggleEnabled(e.target.checked)} - inputProps={{ 'aria-label': 'Enable or disable this version' }} - /> - - )} + {/* Enable/disable applies to every template — built-in, custom, and + gateway-originated — since it only affects control-plane listing. */} + + + {isEnabled ? 'Enabled' : 'Disabled'} + + void handleToggleEnabled(e.target.checked)} + inputProps={{ 'aria-label': 'Enable or disable this version' }} + /> + {/* Custom templates can be deleted entirely (all versions). */} {canDelete && (