Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
HelmRepositoriesApi,
type HelmRepositoryRequest,
type InviteMemberRequest,
KedaTriggerAuthenticationApi,
type KedaTriggerAuthenticationRequest,
type MemberRoleUpdateRequest,
MembersApi,
OrganizationAccountGitRepositoriesApi,
Expand Down Expand Up @@ -53,6 +55,7 @@ const billingApi = new BillingApi()
const customRolesApi = new OrganizationCustomRoleApi()
const membersApi = new MembersApi()
const githubAppApi = new GithubAppApi()
const kedaTriggerAuthApi = new KedaTriggerAuthenticationApi()

export const organizations = createQueryKeys('organizations', {
listCredentials: ({ organizationId }: { organizationId: string }) => ({
Expand Down Expand Up @@ -408,6 +411,26 @@ export const organizations = createQueryKeys('organizations', {
return response.data.results
},
}),
kedaTriggerAuthentications: ({ organizationId }: { organizationId: string }) => ({
queryKey: [organizationId],
async queryFn() {
const response = await kedaTriggerAuthApi.listKedaTriggerAuthentications(organizationId)
return response.data.results
},
}),
kedaTriggerAuthentication: ({
organizationId,
triggerAuthenticationId,
}: {
organizationId: string
triggerAuthenticationId: string
}) => ({
queryKey: [organizationId, triggerAuthenticationId],
async queryFn() {
const response = await kedaTriggerAuthApi.getKedaTriggerAuthentication(organizationId, triggerAuthenticationId)
return response.data
},
}),
})

export const mutations = {
Expand Down Expand Up @@ -784,4 +807,43 @@ export const mutations = {
const response = await billingApi.changePlan(organizationId, { plan })
return response.data
},
async createKedaTriggerAuthentication({
organizationId,
kedaTriggerAuthenticationRequest,
}: {
organizationId: string
kedaTriggerAuthenticationRequest: KedaTriggerAuthenticationRequest
}) {
const response = await kedaTriggerAuthApi.createKedaTriggerAuthentication(
organizationId,
kedaTriggerAuthenticationRequest
)
return response.data
},
async deleteKedaTriggerAuthentication({
organizationId,
triggerAuthenticationId,
}: {
organizationId: string
triggerAuthenticationId: string
}) {
const response = await kedaTriggerAuthApi.deleteKedaTriggerAuthentication(organizationId, triggerAuthenticationId)
return response.data
},
async updateKedaTriggerAuthentication({
organizationId,
triggerAuthenticationId,
kedaTriggerAuthenticationRequest,
}: {
organizationId: string
triggerAuthenticationId: string
kedaTriggerAuthenticationRequest: KedaTriggerAuthenticationRequest
}) {
const response = await kedaTriggerAuthApi.updateKedaTriggerAuthentication(
organizationId,
triggerAuthenticationId,
kedaTriggerAuthenticationRequest
)
return response.data
},
}
3 changes: 3 additions & 0 deletions libs/domains/organizations/feature/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export * from './lib/hooks/use-helm-repository/use-helm-repository'
export * from './lib/hooks/use-invite-members/use-invite-members'
export * from './lib/hooks/use-invoice-url/use-invoice-url'
export * from './lib/hooks/use-invoices/use-invoices'
export * from './lib/hooks/use-create-keda-trigger-authentication/use-create-keda-trigger-authentication'
export * from './lib/hooks/use-keda-trigger-authentication/use-keda-trigger-authentication'
export * from './lib/hooks/use-keda-trigger-authentications/use-keda-trigger-authentications'
export * from './lib/hooks/use-members/use-members'
export * from './lib/hooks/use-organization/use-organization'
export * from './lib/hooks/use-organizations/use-organizations'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { mutations } from '@qovery/domains/organizations/data-access'
import { queries } from '@qovery/state/util-queries'

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

return useMutation(mutations.createKedaTriggerAuthentication, {
onSuccess(_, { organizationId }) {
queryClient.invalidateQueries({
queryKey: queries.organizations.kedaTriggerAuthentications({ organizationId }).queryKey,
})
},
meta: {
notifyOnSuccess: {
title: 'KEDA trigger authentication created',
},
notifyOnError: true,
},
})
}

export default useCreateKedaTriggerAuthentication
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useQuery } from '@tanstack/react-query'
import { queries } from '@qovery/state/util-queries'

export interface UseKedaTriggerAuthenticationProps {
organizationId: string
triggerAuthenticationId: string
enabled?: boolean
}

export function useKedaTriggerAuthentication({
organizationId,
triggerAuthenticationId,
enabled = true,
}: UseKedaTriggerAuthenticationProps) {
return useQuery({
...queries.organizations.kedaTriggerAuthentication({ organizationId, triggerAuthenticationId }),
enabled,
})
}

export default useKedaTriggerAuthentication
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 UseKedaTriggerAuthenticationsProps {
organizationId: string
enabled?: boolean
}

export function useKedaTriggerAuthentications({ organizationId, enabled = true }: UseKedaTriggerAuthenticationsProps) {
return useQuery({
...queries.organizations.kedaTriggerAuthentications({ organizationId }),
enabled,
})
}

export default useKedaTriggerAuthentications
1 change: 1 addition & 0 deletions libs/domains/services/feature/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export * from './lib/hooks/use-recent-services/use-recent-services'
export * from './lib/hooks/use-favorite-services/use-favorite-services'
export * from './lib/pod-statuses-callout/pod-statuses-callout'
export * from './lib/pods-metrics/pods-metrics'
export * from './lib/scaled-object-status/scaled-object-status'
export * from './lib/service-action-toolbar/service-action-toolbar'
export * from './lib/service-deployment-status-label/service-deployment-status-label'
export * from './lib/service-details/service-details'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { ScaledObjectStatusDto } from 'qovery-ws-typescript-axios/dist/api'
import { match } from 'ts-pattern'
import { Badge, Heading, Icon, Section, Skeleton, StatusChip } from '@qovery/shared/ui'
import { useRunningStatus } from '../hooks/use-running-status/use-running-status'

export interface ScaledObjectStatusProps {
environmentId: string
serviceId: string
}

export function ScaledObjectStatus({ environmentId, serviceId }: ScaledObjectStatusProps) {
const { data: runningStatus, isLoading } = useRunningStatus({ environmentId, serviceId })

// Only show for APPLICATION and CONTAINER with scaled_object
if (!runningStatus || !('scaled_object' in runningStatus) || !runningStatus.scaled_object) {
return null
}

const scaledObject = runningStatus.scaled_object as ScaledObjectStatusDto

if (isLoading) {
return (
<Section className="gap-3">
<Heading>Scaled Object</Heading>
<Skeleton height={80} width="100%" />
</Section>
)
}

return (
<Section className="gap-3">
<Heading>Scaled Object (KEDA)</Heading>
<div className="rounded border border-neutral-250 bg-neutral-100">
<div className="border-b border-neutral-250 px-4 py-3">
<div className="flex items-center gap-3">
<Icon iconName="gauge-high" className="text-neutral-400" />
<div className="flex flex-col gap-0.5">
<span className="text-sm font-medium text-neutral-400">{scaledObject.name}</span>
</div>
</div>
</div>

{scaledObject.conditions && scaledObject.conditions.length > 0 && (
<div className="divide-y divide-neutral-250">
{scaledObject.conditions
.filter((condition) => {
// Don't show Fallback at all
if (condition.type === 'Fallback') return false
// Only show Paused if it's True (paused)
if (condition.type === 'Paused' && condition.status !== 'True') return false
// Only show Active if it's True (if False, all scalers have correct values, not an issue)
if (condition.type === 'Active' && condition.status !== 'True') return false
return true
})
.map((condition, index) => {
const chipStatus = match({ type: condition.type, status: condition.status })
// Positive conditions: True = good, False = bad/warning
.with({ type: 'Ready', status: 'True' }, () => 'RUNNING' as const)
.with({ type: 'Ready', status: 'False' }, () => 'ERROR' as const)
.with({ type: 'Active', status: 'True' }, () => 'RUNNING' as const)
.with({ type: 'Active', status: 'False' }, () => 'WARNING' as const)
// Paused: True = bad (paused)
.with({ type: 'Paused', status: 'True' }, () => 'ERROR' as const)
// Default
.otherwise(() => (condition.status === 'True' ? ('RUNNING' as const) : ('WARNING' as const)))

return (
<div key={index} className="flex items-start gap-3 px-4 py-3">
<div className="flex min-w-0 flex-1 flex-col gap-1">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-neutral-400">{condition.type}</span>
<Badge variant="outline" radius="full" className="gap-2">
<StatusChip status={chipStatus} />
<span className="text-neutral-400">{condition.status}</span>
</Badge>
</div>
{condition.reason && <span className="text-xs text-neutral-350">Reason: {condition.reason}</span>}
{condition.message && <span className="text-xs text-neutral-350">{condition.message}</span>}
</div>
</div>
)
})}
</div>
)}
</div>
</Section>
)
}

export default ScaledObjectStatus
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { type HelmGeneralData } from '@qovery/pages/services'
import { isHelmGitSource, isHelmRepositorySource, isJobContainerSource, isJobGitSource } from '@qovery/shared/enums'
import { type ApplicationGeneralData, type JobGeneralData } from '@qovery/shared/interfaces'
import { joinArgsWithQuotes, parseCmd } from '@qovery/shared/util-js'
import { convertAutoscalingResponseToRequest } from '@qovery/shared/util-services'
import PageSettingsGeneral from '../../ui/page-settings-general/page-settings-general'

export const handleGitApplicationSubmit = (
Expand All @@ -36,15 +37,17 @@ export const handleGitApplicationSubmit = (
labelsGroups: OrganizationLabelsGroupEnrichedResponse[],
annotationsGroups: OrganizationAnnotationsGroupResponse[]
): ApplicationEditRequest => {
const { autoscaling, ...applicationWithoutAutoscaling } = application
let cloneApplication: ApplicationEditRequest = {
...application,
...applicationWithoutAutoscaling,
dockerfile_path: undefined,
docker_target_build_stage: undefined,
git_repository: undefined,
name: data.name,
description: data.description || '',
icon_uri: data.icon_uri,
auto_deploy: data.auto_deploy,
autoscaling: convertAutoscalingResponseToRequest(autoscaling),
}
cloneApplication.auto_deploy = data.auto_deploy

Expand Down Expand Up @@ -87,8 +90,9 @@ export const handleContainerSubmit = (
labelsGroups: OrganizationLabelsGroupEnrichedResponse[],
annotationsGroups: OrganizationAnnotationsGroupResponse[]
): ContainerRequest => {
const { autoscaling, ...containerWithoutAutoscaling } = container
return {
...container,
...containerWithoutAutoscaling,
name: data.name,
description: data.description || '',
icon_uri: data.icon_uri,
Expand All @@ -98,6 +102,7 @@ export const handleContainerSubmit = (
arguments: data.cmd_arguments?.length ? parseCmd(data.cmd_arguments) : [],
entrypoint: data.image_entry_point || '',
registry_id: data.registry || '',
autoscaling: convertAutoscalingResponseToRequest(autoscaling),
annotations_groups: annotationsGroups.filter((group) => data.annotations_groups?.includes(group.id)),
labels_groups: labelsGroups.filter((group) => data.labels_groups?.includes(group.id)),
}
Expand Down
Loading
Loading