diff --git a/libs/domains/observability/feature/src/lib/alerting/alert-rules-overview/alert-rules-overview.tsx b/libs/domains/observability/feature/src/lib/alerting/alert-rules-overview/alert-rules-overview.tsx index c5492aa18cf..c1491ee01c0 100644 --- a/libs/domains/observability/feature/src/lib/alerting/alert-rules-overview/alert-rules-overview.tsx +++ b/libs/domains/observability/feature/src/lib/alerting/alert-rules-overview/alert-rules-overview.tsx @@ -4,6 +4,7 @@ import { type PropsWithChildren, type ReactNode, useMemo, useState } from 'react import { useNavigate } from 'react-router-dom' import { match } from 'ts-pattern' import { type AnyService } from '@qovery/domains/services/data-access' +import { useDeploymentStatus } from '@qovery/domains/services/feature' import { APPLICATION_MONITORING_ALERTS_URL, APPLICATION_MONITORING_ALERT_EDIT_URL, @@ -101,6 +102,10 @@ export function AlertRulesOverview({ const { openModal, closeModal } = useModal() const { openModalConfirmation } = useModalConfirmation() const navigate = useNavigate() + const { data: deploymentStatus } = useDeploymentStatus({ + environmentId: service?.environment?.id, + serviceId: service?.id, + }) const { mutate: deleteAlertRule } = useDeleteAlertRule({ organizationId }) @@ -156,6 +161,13 @@ export function AlertRulesOverview({ [selectedAlertRuleIds.size, selectableAlertRules.length] ) + const canCreateAlerts = useMemo(() => { + return ( + deploymentStatus?.service_deployment_status !== undefined && + deploymentStatus?.service_deployment_status !== 'NEVER_DEPLOYED' + ) + }, [deploymentStatus]) + const toggleSelectAll = (checked: boolean) => { if (checked) { const allIds = new Set(selectableAlertRules.map((alertRule) => alertRule.id)) @@ -240,10 +252,14 @@ export function AlertRulesOverview({ )}

{onCreateKeyAlerts && ( - + +
+ +
+
)} ) : ( diff --git a/libs/domains/observability/feature/src/lib/alerting/alerting-creation-flow/alerting-creation-flow.tsx b/libs/domains/observability/feature/src/lib/alerting/alerting-creation-flow/alerting-creation-flow.tsx index 7ff45e92059..48330b0e0a9 100644 --- a/libs/domains/observability/feature/src/lib/alerting/alerting-creation-flow/alerting-creation-flow.tsx +++ b/libs/domains/observability/feature/src/lib/alerting/alerting-creation-flow/alerting-creation-flow.tsx @@ -164,7 +164,7 @@ export function AlertingCreationFlow({ service?.min_running_instances !== service?.max_running_instances if (!containerName) return - if (hasPublicPort && !ingressName) return + if (hasPublicPort && !(ingressName || httpRouteName)) return if (hasAutoscaling && !hpaName) return try { diff --git a/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.spec.tsx b/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.spec.tsx index 2444abb1b95..a4b331bcd48 100644 --- a/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.spec.tsx +++ b/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.spec.tsx @@ -1,5 +1,5 @@ import { AlertRuleState } from 'qovery-typescript-axios' -import { renderWithProviders, screen } from '@qovery/shared/util-tests' +import { renderWithProviders, screen, within } from '@qovery/shared/util-tests' import { ServiceAlerting } from './service-alerting' const mockUseParams = jest.fn() @@ -8,6 +8,7 @@ const mockUseAlertRulesGhosted = jest.fn() const mockUseDeleteAlertRule = jest.fn() const mockUseEnvironment = jest.fn() const mockUseService = jest.fn() +const mockUseDeploymentStatus = jest.fn() jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -32,6 +33,7 @@ jest.mock('../../hooks/use-environment/use-environment', () => ({ jest.mock('@qovery/domains/services/feature', () => ({ useService: (params: unknown) => mockUseService(params), + useDeploymentStatus: (params: unknown) => mockUseDeploymentStatus(params), })) describe('ServiceAlerting', () => { @@ -93,6 +95,30 @@ describe('ServiceAlerting', () => { mockUseDeleteAlertRule.mockReturnValue({ mutate: jest.fn(), }) + mockUseDeploymentStatus.mockReturnValue({ + data: { service_deployment_status: 'DEPLOYED' }, + isFetched: true, + }) + }) + + it('should display tooltip explaining alerts require deployment when service was never deployed', async () => { + mockUseDeploymentStatus.mockReturnValue({ + data: { service_deployment_status: 'NEVER_DEPLOYED' }, + isFetched: true, + }) + + const { userEvent } = renderWithProviders() + + const headerToolbar = screen.getByRole('heading', { name: 'Alert rules' }).parentElement + expect(headerToolbar).toBeInTheDocument() + const newAlertButton = within(headerToolbar as HTMLElement).getByRole('button', { name: /new alert/i }) + await userEvent.hover(newAlertButton.parentElement ?? newAlertButton) + + expect( + await screen.findByRole('tooltip', { + name: 'You need to deploy your service to create alerts', + }) + ).toBeInTheDocument() }) it('should render loader when environment is not loaded', () => { diff --git a/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.tsx b/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.tsx index c31f1861137..4fd3c6985c1 100644 --- a/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.tsx +++ b/libs/domains/observability/feature/src/lib/service/service-alerting/service-alerting.tsx @@ -1,8 +1,8 @@ -import { type PropsWithChildren } from 'react' +import { type PropsWithChildren, useMemo } from 'react' import { useParams } from 'react-router-dom' import { type AnyService } from '@qovery/domains/services/data-access' -import { useService } from '@qovery/domains/services/feature' -import { Button, Chart, Heading, Icon, Section, useModal } from '@qovery/shared/ui' +import { useDeploymentStatus, useService } from '@qovery/domains/services/feature' +import { Button, Chart, Heading, Icon, Section, Tooltip, useModal } from '@qovery/shared/ui' import { AlertRulesOverview } from '../../alerting/alert-rules-overview/alert-rules-overview' import { CreateKeyAlertsModal } from '../../alerting/create-key-alerts-modal/create-key-alerts-modal' import { useEnvironment } from '../../hooks/use-environment/use-environment' @@ -15,6 +15,10 @@ interface ServiceAlertingContentProps extends PropsWithChildren { function ServiceAlertingContent({ organizationId, projectId, service, children }: ServiceAlertingContentProps) { const { openModal, closeModal } = useModal() + const { data: deploymentStatus } = useDeploymentStatus({ + environmentId: service?.environment?.id, + serviceId: service?.id, + }) const createKeyAlertsModal = () => { openModal({ @@ -32,15 +36,33 @@ function ServiceAlertingContent({ organizationId, projectId, service, children } }) } + const canCreateAlerts = useMemo(() => { + return ( + deploymentStatus?.service_deployment_status !== undefined && + deploymentStatus?.service_deployment_status !== 'NEVER_DEPLOYED' + ) + }, [deploymentStatus]) + return (
Alert rules - + +
+ +
+