Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 108 additions & 24 deletions apps/console/src/routeTree.gen.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Navigate, createFileRoute, useParams } from '@tanstack/react-router'

export const Route = createFileRoute('/_authenticated/organization/$organizationId/settings/agents/')({
component: RouteComponent,
})

function RouteComponent() {
const { organizationId } = useParams({ strict: false })

if (!organizationId) return null

return <Navigate to="/organization/$organizationId/settings/agents/tokens" params={{ organizationId }} replace />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'
import { SettingsAgentMcps } from '@qovery/domains/organizations/feature'

export const Route = createFileRoute('/_authenticated/organization/$organizationId/settings/agents/mcps')({
component: SettingsAgentMcps,
})
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createFileRoute, useNavigate, useParams } from '@tanstack/react-router'
import { Outlet, createFileRoute, useNavigate, useParams } from '@tanstack/react-router'
import { useFeatureFlagEnabled } from 'posthog-js/react'
import { useEffect } from 'react'
import { SettingsAgentPersonalization } from '@qovery/domains/organizations/feature'

export const Route = createFileRoute('/_authenticated/organization/$organizationId/settings/agents')({
component: RouteComponent,
Expand All @@ -24,5 +23,5 @@ function RouteComponent() {

if (!isAgenticWorkflowEnabled) return null

return <SettingsAgentPersonalization />
return <Outlet />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'
import { SettingsAgentTokens } from '@qovery/domains/organizations/feature'

export const Route = createFileRoute('/_authenticated/organization/$organizationId/settings/agents/tokens')({
component: SettingsAgentTokens,
})
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,17 @@ function RouteComponent() {
icon: 'sparkles' as const,
children: [
{ title: 'Copilot', to: `${pathSettings}/ai-copilot` },
...(isAgenticWorkflowEnabled ? [{ title: 'Agents', to: `${pathSettings}/agents` }] : []),
{ title: 'Skills', to: `${pathSettings}/skills` },
{ title: 'MCP server', to: `${pathSettings}/mcp-server` },
],
}

const agentsLink = {
type: 'group',
title: 'Agent',
icon: 'robot' as const,
children: [
{ title: 'Token', to: `${pathSettings}/agents/tokens` },
{ title: 'MCP', to: `${pathSettings}/agents/mcps` },
],
}

Expand All @@ -129,6 +137,7 @@ function RouteComponent() {
webhookLink,
apiTokenLink,
aiLink,
...(isAgenticWorkflowEnabled ? [agentsLink] : []),
...(isOrganizationAdmin ? [dangerZoneLink] : []),
]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { MCPServersApi, OrganizationMainCallsApi, OrganizationOnboardingStatusEnum } from 'qovery-typescript-axios'
import {
LLMProvidersApi,
LlmProviderScope,
LlmProviderType,
MCPServersApi,
OrganizationMainCallsApi,
OrganizationOnboardingStatusEnum,
} from 'qovery-typescript-axios'
import { mutations, organizations } from './domains-organizations-data-access'

describe('organizations.onboarding', () => {
Expand Down Expand Up @@ -104,3 +111,60 @@ describe('MCP server mutations', () => {
expect(MCPServersApi.prototype.deleteMcpServer).toHaveBeenCalledWith('mcp-1')
})
})

describe('organizations.llmProviders', () => {
it('should return organization LLM providers', async () => {
const mockData = [{ id: 'provider-1', name: 'Claude' }]
jest
.spyOn(LLMProvidersApi.prototype, 'listLlmProviders')
.mockResolvedValue({ data: { results: mockData } } as never)

const query = organizations.llmProviders({ organizationId: 'org-1' })
const result = await query.queryFn({} as never)

expect(LLMProvidersApi.prototype.listLlmProviders).toHaveBeenCalledWith('org-1')
expect(result).toEqual(mockData)
expect(query.queryKey).toContain('org-1')
})
})

describe('LLM provider mutations', () => {
const llmProviderRequest = {
name: 'Claude',
type: LlmProviderType.CLAUDE,
credential: 'secret',
scope: LlmProviderScope.USER,
}

it('should create an LLM provider', async () => {
const mockData = { id: 'provider-1', ...llmProviderRequest }
jest.spyOn(LLMProvidersApi.prototype, 'createLlmProvider').mockResolvedValue({ data: mockData } as never)

const result = await mutations.createLlmProvider({ organizationId: 'org-1', llmProviderRequest })

expect(LLMProvidersApi.prototype.createLlmProvider).toHaveBeenCalledWith('org-1', llmProviderRequest)
expect(result).toEqual(mockData)
})

it('should edit an LLM provider', async () => {
const mockData = { id: 'provider-1', ...llmProviderRequest }
jest.spyOn(LLMProvidersApi.prototype, 'editLlmProvider').mockResolvedValue({ data: mockData } as never)

const result = await mutations.editLlmProvider({
organizationId: 'org-1',
llmProviderId: 'provider-1',
llmProviderRequest,
})

expect(LLMProvidersApi.prototype.editLlmProvider).toHaveBeenCalledWith('provider-1', llmProviderRequest)
expect(result).toEqual(mockData)
})

it('should delete an LLM provider', async () => {
jest.spyOn(LLMProvidersApi.prototype, 'deleteLlmProvider').mockResolvedValue({ data: undefined } as never)

await mutations.deleteLlmProvider({ organizationId: 'org-1', llmProviderId: 'provider-1' })

expect(LLMProvidersApi.prototype.deleteLlmProvider).toHaveBeenCalledWith('provider-1')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
HelmRepositoriesApi,
type HelmRepositoryRequest,
type InviteMemberRequest,
LLMProvidersApi,
type LlmProviderRequest,
MCPServersApi,
type McpServerRequest,
type MemberRoleUpdateRequest,
Expand Down Expand Up @@ -62,6 +64,7 @@ const billingApi = new BillingApi()
const customRolesApi = new OrganizationCustomRoleApi()
const membersApi = new MembersApi()
const mcpServersApi = new MCPServersApi()
const llmProvidersApi = new LLMProvidersApi()
const githubAppApi = new GithubAppApi()
const argoCdApi = new ArgoCDApi()

Expand Down Expand Up @@ -122,6 +125,13 @@ export const organizations = createQueryKeys('organizations', {
return response.data.results
},
}),
llmProviders: ({ organizationId }: { organizationId: string }) => ({
queryKey: [organizationId],
async queryFn() {
const response = await llmProvidersApi.listLlmProviders(organizationId)
return response.data.results
},
}),
containerRegistry: ({
organizationId,
containerRegistryId,
Expand Down Expand Up @@ -674,6 +684,31 @@ export const mutations = {
const response = await mcpServersApi.deleteMcpServer(mcpServerId)
return response.data
},
async createLlmProvider({
organizationId,
llmProviderRequest,
}: {
organizationId: string
llmProviderRequest: LlmProviderRequest
}) {
const response = await llmProvidersApi.createLlmProvider(organizationId, llmProviderRequest)
return response.data
},
async editLlmProvider({
llmProviderId,
llmProviderRequest,
}: {
organizationId: string
llmProviderId: string
llmProviderRequest: LlmProviderRequest
}) {
const response = await llmProvidersApi.editLlmProvider(llmProviderId, llmProviderRequest)
return response.data
},
async deleteLlmProvider({ llmProviderId }: { organizationId: string; llmProviderId: string }) {
const response = await llmProvidersApi.deleteLlmProvider(llmProviderId)
return response.data
},
async deleteGitToken({ organizationId, gitTokenId }: { organizationId: string; gitTokenId: string }) {
const response = await organizationApi.deleteGitToken(organizationId, gitTokenId)
return response.data
Expand Down
5 changes: 5 additions & 0 deletions libs/domains/organizations/feature/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export * from './lib/hooks/use-create-mcp-server/use-create-mcp-server'
export * from './lib/hooks/use-create-qovery-mcp-server/use-create-qovery-mcp-server'
export * from './lib/hooks/use-edit-mcp-server/use-edit-mcp-server'
export * from './lib/hooks/use-delete-mcp-server/use-delete-mcp-server'
export * from './lib/hooks/use-llm-providers/use-llm-providers'
export * from './lib/hooks/use-create-llm-provider/use-create-llm-provider'
export * from './lib/hooks/use-edit-llm-provider/use-edit-llm-provider'
export * from './lib/hooks/use-delete-llm-provider/use-delete-llm-provider'
export * from './lib/invoice-banner/invoice-banner'
export * from './lib/settings-general/settings-general'
export * from './lib/settings-labels-annotations/settings-labels-annotations'
Expand All @@ -119,6 +123,7 @@ export * from './lib/settings-ai-skills/settings-ai-skills'
export * from './lib/settings-agent-personalization/settings-agent-personalization'
export * from './lib/mcp-server-create-edit-modal/mcp-server-create-edit-modal'
export * from './lib/mcp-server-setting/mcp-server-setting'
export * from './lib/llm-provider-setting/llm-provider-setting'
export * from './lib/settings-argocd-integration/settings-argocd-integration'
export * from './lib/settings-danger-zone/settings-danger-zone'
export * from './lib/settings-billing-details/settings-billing-details'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { mutations } from '@qovery/domains/organizations/data-access'
import { queries } from '@qovery/state/util-queries'

export function useCreateLlmProvider() {
const queryClient = useQueryClient()

return useMutation(mutations.createLlmProvider, {
onSuccess(_, { organizationId }) {
queryClient.invalidateQueries({ queryKey: queries.organizations.llmProviders({ organizationId }).queryKey })
},
meta: {
notifyOnSuccess: { title: 'Your token has been created' },
notifyOnError: true,
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { mutations } from '@qovery/domains/organizations/data-access'
import { queries } from '@qovery/state/util-queries'

export function useDeleteLlmProvider() {
const queryClient = useQueryClient()

return useMutation(mutations.deleteLlmProvider, {
onSuccess(_, { organizationId }) {
queryClient.invalidateQueries({ queryKey: queries.organizations.llmProviders({ organizationId }).queryKey })
},
meta: {
notifyOnSuccess: { title: 'Your token has been deleted' },
notifyOnError: true,
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { mutations } from '@qovery/domains/organizations/data-access'
import { queries } from '@qovery/state/util-queries'

export function useEditLlmProvider() {
const queryClient = useQueryClient()

return useMutation(mutations.editLlmProvider, {
onSuccess(_, { organizationId }) {
queryClient.invalidateQueries({ queryKey: queries.organizations.llmProviders({ organizationId }).queryKey })
},
meta: {
notifyOnSuccess: { title: 'Your token has been updated' },
notifyOnError: true,
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useQuery } from '@tanstack/react-query'
import { queries } from '@qovery/state/util-queries'

export interface UseLlmProvidersProps {
organizationId: string
suspense?: boolean
enabled?: boolean
}

export function useLlmProviders({ organizationId, suspense = false, enabled = true }: UseLlmProvidersProps) {
return useQuery({
...queries.organizations.llmProviders({ organizationId }),
suspense,
enabled,
})
}
Loading
Loading