diff --git a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/configure.tsx b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/configure.tsx index 35dd0eb6349..568ee5be3c6 100644 --- a/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/configure.tsx +++ b/apps/console-v5/src/routes/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/configure.tsx @@ -1,4 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' +import { JobConfiguration } from '@qovery/domains/service-settings/feature' +import { useDocumentTitle } from '@qovery/shared/util-hooks' export const Route = createFileRoute( '/_authenticated/organization/$organizationId/project/$projectId/environment/$environmentId/service/$serviceId/settings/configure' @@ -7,5 +9,7 @@ export const Route = createFileRoute( }) function RouteComponent() { - return
Configuration
+ useDocumentTitle('Job configuration - Service settings') + + return } diff --git a/libs/domains/service-settings/feature/src/index.ts b/libs/domains/service-settings/feature/src/index.ts index 96ffef2c08c..558933d1b37 100644 --- a/libs/domains/service-settings/feature/src/index.ts +++ b/libs/domains/service-settings/feature/src/index.ts @@ -13,3 +13,4 @@ export * from './lib/terraform-variables-settings/terraform-variables-table/terr export * from './lib/helm-values-override-file-settings/helm-values-override-file-settings' export * from './lib/helm-values-override-arguments-settings/helm-values-override-arguments-settings' export * from './lib/helm-networking-settings/helm-networking-settings' +export * from './lib/job-configuration/job-configuration' diff --git a/libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.spec.tsx b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.spec.tsx similarity index 82% rename from libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.spec.tsx rename to libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.spec.tsx index 8e7b35d21a2..2b232539a4c 100644 --- a/libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.spec.tsx +++ b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.spec.tsx @@ -2,9 +2,9 @@ import { wrapWithReactHookForm } from '__tests__/utils/wrap-with-react-hook-form import { ServiceTypeEnum } from '@qovery/shared/enums' import { type JobConfigureData, type JobGeneralData } from '@qovery/shared/interfaces' import { renderWithProviders, screen } from '@qovery/shared/util-tests' -import JobConfigureSettings, { type JobConfigureSettingsProps } from './job-configure-settings' +import { JobConfigurationForm, type JobConfigurationFormProps } from './job-configuration-form' -const props: JobConfigureSettingsProps = { +const props: JobConfigurationFormProps = { jobType: ServiceTypeEnum.CRON_JOB, } @@ -19,10 +19,10 @@ const defaultValues: JobConfigureData & Pick { +describe('JobConfigurationForm', () => { it('should render successfully', () => { const { baseElement } = renderWithProviders( - wrapWithReactHookForm(, { + wrapWithReactHookForm(, { defaultValues, }) ) @@ -34,7 +34,7 @@ describe('JobConfigureSettings', () => { it('should render 3 enabled box and 3 inputs', () => { renderWithProviders( - wrapWithReactHookForm(, { + wrapWithReactHookForm(, { defaultValues, }) ) @@ -49,7 +49,7 @@ describe('JobConfigureSettings', () => { it('should render 4 inputs and 1 select', async () => { renderWithProviders( - wrapWithReactHookForm(, { + wrapWithReactHookForm(, { defaultValues, }) ) @@ -60,7 +60,7 @@ describe('JobConfigureSettings', () => { it('should display the cron value in a human readable way', async () => { const { userEvent } = renderWithProviders( - wrapWithReactHookForm(, { + wrapWithReactHookForm(, { defaultValues, }) ) diff --git a/libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.tsx b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.tsx similarity index 61% rename from libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.tsx rename to libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.tsx index 5eac590df51..ad80cb70495 100644 --- a/libs/shared/console-shared/src/lib/job-configure-settings/ui/job-configure-settings.tsx +++ b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration-form/job-configuration-form.tsx @@ -1,30 +1,25 @@ -// TODO: Refactor cronstrue usage to only use formatCronExpression // eslint-disable-next-line @typescript-eslint/no-restricted-imports import cronstrue from 'cronstrue' import { Controller, useFormContext } from 'react-hook-form' import { TimezoneSetting } from '@qovery/domains/services/feature' +import { EntrypointCmdInputs } from '@qovery/shared/console-shared' import { type JobType, ServiceTypeEnum } from '@qovery/shared/enums' import { type JobConfigureData } from '@qovery/shared/interfaces' -import { Callout, EnableBox, ExternalLink, Heading, Icon, InputText, LoaderSpinner, Section } from '@qovery/shared/ui' +import { Callout, EnableBox, ExternalLink, Heading, Icon, InputText, Section } from '@qovery/shared/ui' import { formatCronExpression } from '@qovery/shared/util-js' -import EntrypointCmdInputs from '../../entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs' -export interface JobConfigureSettingsProps { +export interface JobConfigurationFormProps { jobType: JobType - loading?: boolean } -export function JobConfigureSettings(props: JobConfigureSettingsProps) { - const { loading } = props +export function JobConfigurationForm(props: JobConfigurationFormProps) { const { control, watch } = useFormContext() const watchSchedule = watch('schedule') const watchTimezone = watch('timezone') ?? 'Etc/UTC' const watchMaxDuration = watch('max_duration') - return loading ? ( - - ) : ( + return ( <> {props.jobType === ServiceTypeEnum.CRON_JOB ? (
@@ -62,71 +57,75 @@ export function JobConfigureSettings(props: JobConfigureSettingsProps) {
) : ( -
- Events -

- Select one or more event where the job should be executed and the command to execute. -

+
+
+ Events +

+ Select one or more event where the job should be executed and the command to execute. +

+
- ( - - - - )} - /> +
+ ( + + + + )} + /> - ( - - - - )} - /> + ( + + + + )} + /> - ( - - - - )} - /> + ( + + + + )} + /> +
)} @@ -201,5 +200,3 @@ export function JobConfigureSettings(props: JobConfigureSettingsProps) { ) } - -export default JobConfigureSettings diff --git a/libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.spec.tsx b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.spec.tsx similarity index 88% rename from libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.spec.tsx rename to libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.spec.tsx index 204e7d2cc46..9970c74f8cf 100644 --- a/libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.spec.tsx +++ b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.spec.tsx @@ -1,8 +1,9 @@ import { type Job } from '@qovery/domains/services/data-access' import * as servicesDomain from '@qovery/domains/services/feature' import { cronjobFactoryMock, lifecycleJobFactoryMock } from '@qovery/shared/factories' +import { Section } from '@qovery/shared/ui' import { renderWithProviders, screen, waitFor } from '@qovery/shared/util-tests' -import PageSettingsConfigureJobFeature from './page-settings-configure-job-feature' +import { JobConfiguration } from './job-configuration' const useServiceSpy = jest.spyOn(servicesDomain, 'useService') as jest.Mock const useEditServiceSpy = jest.spyOn(servicesDomain, 'useEditService') as jest.Mock @@ -11,6 +12,24 @@ const mockJobApplication = cronjobFactoryMock(1)[0] as Job const mockLifecycleJobApplication = lifecycleJobFactoryMock(1)[0] as Job const mockEditService = jest.fn() +jest.mock('@tanstack/react-router', () => ({ + ...jest.requireActual('@tanstack/react-router'), + useParams: () => ({ + organizationId: 'org-1', + projectId: 'project-1', + environmentId: 'env-1', + serviceId: 'service-1', + }), +})) + +const render = () => { + return renderWithProviders( +
+ +
+ ) +} + describe('PageSettingsPortsFeature with CRON JOB service', () => { beforeEach(() => { useServiceSpy.mockReturnValue({ @@ -23,7 +42,7 @@ describe('PageSettingsPortsFeature with CRON JOB service', () => { }) it('should call edit service with correct payload', async () => { - const { userEvent } = renderWithProviders() + const { userEvent } = render() const inputCron = screen.getByLabelText('Schedule - Cron expression') const inputNbRestarts = screen.getByLabelText('Number of restarts') @@ -72,7 +91,7 @@ describe('PageSettingsPortsFeature with LIFECYCLE JOB service', () => { }) }) it('should call edit service with correct payload', async () => { - const { userEvent } = renderWithProviders() + const { userEvent } = render() const checkboxDelete = screen.getByLabelText('Delete') await userEvent.click(checkboxDelete) diff --git a/libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.tsx b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.tsx similarity index 61% rename from libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.tsx rename to libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.tsx index 69a2b9dfd4c..c42bc5d92b0 100644 --- a/libs/pages/application/src/lib/feature/page-settings-configure-job-feature/page-settings-configure-job-feature.tsx +++ b/libs/domains/service-settings/feature/src/lib/job-configuration/job-configuration.tsx @@ -1,15 +1,17 @@ +import { useParams } from '@tanstack/react-router' import { FormProvider, useForm } from 'react-hook-form' -import { useParams } from 'react-router-dom' import { match } from 'ts-pattern' import { useEditService, useService } from '@qovery/domains/services/feature' +import { SettingsHeading } from '@qovery/shared/console-shared' +import { ServiceTypeEnum } from '@qovery/shared/enums' import { type JobConfigureData, type JobGeneralData } from '@qovery/shared/interfaces' +import { Button, Section } from '@qovery/shared/ui' import { joinArgsWithQuotes, parseCmd } from '@qovery/shared/util-js' -import PageSettingsConfigureJob from '../../ui/page-settings-configure-job/page-settings-configure-job' +import { JobConfigurationForm } from './job-configuration-form/job-configuration-form' -export function PageSettingsConfigureJobFeature() { - const { organizationId = '', projectId = '', environmentId = '', applicationId = '' } = useParams() - - const { data: service } = useService({ serviceId: applicationId, serviceType: 'JOB' }) +export const JobConfiguration = () => { + const { organizationId = '', projectId = '', environmentId = '', serviceId = '' } = useParams({ strict: false }) + const { data: service } = useService({ serviceId, serviceType: 'JOB', suspense: true }) const { mutate: editService, isLoading: isLoadingEditService } = useEditService({ organizationId, projectId, @@ -121,10 +123,48 @@ export function PageSettingsConfigureJobFeature() { if (!service) return return ( - - - +
+
+ +
+
+ 'Job configuration') + .with({ service_type: 'JOB', job_type: 'LIFECYCLE' }, () => 'Triggers') + .otherwise(() => '')} + description={match(service) + .with( + { service_type: 'JOB', job_type: 'CRON' }, + () => 'Job configuration allows you to control the behavior of your service.' + ) + .with( + { service_type: 'JOB', job_type: 'LIFECYCLE' }, + () => 'Define the events triggering the execution of this job and the commands to execute.' + ) + .otherwise(() => '')} + /> +
+
+ +
+ +
+ +
+
+
+
+
+
) } - -export default PageSettingsConfigureJobFeature diff --git a/libs/pages/application/src/lib/feature/page-settings-feature/page-settings-feature.tsx b/libs/pages/application/src/lib/feature/page-settings-feature/page-settings-feature.tsx index 44932af12d3..f7c85f5af44 100644 --- a/libs/pages/application/src/lib/feature/page-settings-feature/page-settings-feature.tsx +++ b/libs/pages/application/src/lib/feature/page-settings-feature/page-settings-feature.tsx @@ -4,7 +4,6 @@ import { useService } from '@qovery/domains/services/feature' import { isJobGitSource } from '@qovery/shared/enums' import { APPLICATION_SETTINGS_ADVANCED_SETTINGS_URL, - APPLICATION_SETTINGS_CONFIGURE_URL, APPLICATION_SETTINGS_DANGER_ZONE_URL, APPLICATION_SETTINGS_DOCKERFILE_URL, APPLICATION_SETTINGS_HEALTHCHECKS_URL, @@ -63,15 +62,6 @@ export function PageSettingsFeature() { url: pathSettings + APPLICATION_SETTINGS_DOCKERFILE_URL, } - const configureJobSetting = { - title: match(service) - .with({ service_type: 'JOB', job_type: 'CRON' }, () => 'Job configuration') - .with({ service_type: 'JOB', job_type: 'LIFECYCLE' }, () => 'Triggers') - .otherwise(() => ''), - icon: IconAwesomeEnum.GEARS, - url: pathSettings + APPLICATION_SETTINGS_CONFIGURE_URL, - } - const healthchecksSettings = { title: 'Health Checks', icon: IconAwesomeEnum.SHIELD_CHECK, @@ -128,7 +118,6 @@ export function PageSettingsFeature() { ]) .with({ serviceType: 'JOB' }, (s) => [ ...(s.job_type === 'LIFECYCLE' && isJobGitSource(s.source) ? [dockerfileSetting] : []), - configureJobSetting, advancedSettings, dangerzoneSettings, ]) diff --git a/libs/pages/application/src/lib/router/router.tsx b/libs/pages/application/src/lib/router/router.tsx index 992ef5a87e0..9b2dbb297ff 100644 --- a/libs/pages/application/src/lib/router/router.tsx +++ b/libs/pages/application/src/lib/router/router.tsx @@ -1,6 +1,5 @@ import { APPLICATION_SETTINGS_ADVANCED_SETTINGS_URL, - APPLICATION_SETTINGS_CONFIGURE_URL, APPLICATION_SETTINGS_DANGER_ZONE_URL, APPLICATION_SETTINGS_DOCKERFILE_URL, APPLICATION_SETTINGS_NETWORKING_URL, @@ -14,7 +13,6 @@ import { type Route, } from '@qovery/shared/routes' import PageSettingsAdvancedFeature from '../feature/page-settings-advanced-feature/page-settings-advanced-feature' -import PageSettingsConfigureJobFeature from '../feature/page-settings-configure-job-feature/page-settings-configure-job-feature' import PageSettingsDangerZoneFeature from '../feature/page-settings-danger-zone-feature/page-settings-danger-zone-feature' import { PageSettingsDockerfileFeature } from '../feature/page-settings-dockerfile-feature/page-settings-dockerfile-feature' import { PageSettingsFeature } from '../feature/page-settings-feature/page-settings-feature' @@ -42,10 +40,6 @@ export const ROUTER_APPLICATION_SETTINGS: Route[] = [ path: APPLICATION_SETTINGS_DOCKERFILE_URL, component: , }, - { - path: APPLICATION_SETTINGS_CONFIGURE_URL, - component: , - }, { path: APPLICATION_SETTINGS_ADVANCED_SETTINGS_URL, component: , diff --git a/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.spec.tsx b/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.spec.tsx deleted file mode 100644 index 90de9338bd1..00000000000 --- a/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.spec.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { wrapWithReactHookForm } from '__tests__/utils/wrap-with-react-hook-form' -import { type Job } from '@qovery/domains/services/data-access' -import { cronjobFactoryMock } from '@qovery/shared/factories' -import { type JobConfigureData, type JobGeneralData } from '@qovery/shared/interfaces' -import { renderWithProviders } from '@qovery/shared/util-tests' -import PageSettingsConfigureJob, { type PageSettingsConfigureJobProps } from './page-settings-configure-job' - -const props: PageSettingsConfigureJobProps = { - service: cronjobFactoryMock(1)[0] as Job, - loading: false, - onSubmit: jest.fn(), -} - -describe('PageSettingsDangerZone', () => { - it('should render successfully', () => { - const { baseElement } = renderWithProviders( - wrapWithReactHookForm>( - , - { - defaultValues: { - max_duration: 1, - nb_restarts: 1, - port: 3000, - schedule: '0 0 * * *', - cmd_arguments: '', - cmd: [''], - }, - } - ) - ) - expect(baseElement).toBeTruthy() - }) -}) diff --git a/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.tsx b/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.tsx deleted file mode 100644 index 6a01f299cdb..00000000000 --- a/libs/pages/application/src/lib/ui/page-settings-configure-job/page-settings-configure-job.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useFormContext } from 'react-hook-form' -import { match } from 'ts-pattern' -import { type Job } from '@qovery/domains/services/data-access' -import { JobConfigureSettings, SettingsHeading } from '@qovery/shared/console-shared' -import { ServiceTypeEnum } from '@qovery/shared/enums' -import { Button, Section } from '@qovery/shared/ui' - -export interface PageSettingsConfigureJobProps { - service: Job - onSubmit: () => void - loading: boolean -} - -export function PageSettingsConfigureJob({ service, loading, onSubmit }: PageSettingsConfigureJobProps) { - const { formState } = useFormContext() - - return ( -
-
- 'Job configuration') - .with({ service_type: 'JOB', job_type: 'LIFECYCLE' }, () => 'Triggers') - .otherwise(() => '')} - description={match(service) - .with( - { service_type: 'JOB', job_type: 'CRON' }, - () => 'Job configuration allows you to control the behavior of your service.' - ) - .with( - { service_type: 'JOB', job_type: 'LIFECYCLE' }, - () => 'Define the events triggering the execution of this job and the commands to execute.' - ) - .otherwise(() => '')} - /> -
- -
- -
- -
-
- ) -} - -export default PageSettingsConfigureJob diff --git a/libs/shared/console-shared/src/index.ts b/libs/shared/console-shared/src/index.ts index 1d2d98526d6..12df7b27b23 100644 --- a/libs/shared/console-shared/src/index.ts +++ b/libs/shared/console-shared/src/index.ts @@ -4,7 +4,6 @@ export * from './lib/credit-card-form/ui/credit-card-form' export * from './lib/github-application-callback/github-application-callback-feature/github-application-callback-feature' export * from './lib/force-run-modal/feature/force-run-modal-feature' export * from './lib/force-run-modal/ui/force-run-modal' -export * from './lib/job-configure-settings/ui/job-configure-settings' export * from './lib/entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs' export * from './lib/flow-create-port/ui/flow-create-port/flow-create-port' export * from './lib/flow-create-port/ui/crud-modal/crud-modal' diff --git a/libs/shared/console-shared/src/lib/entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs.tsx b/libs/shared/console-shared/src/lib/entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs.tsx index d66253921b0..96ac153478e 100644 --- a/libs/shared/console-shared/src/lib/entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs.tsx +++ b/libs/shared/console-shared/src/lib/entrypoint-cmd-inputs/ui/entrypoint-cmd-inputs.tsx @@ -28,7 +28,7 @@ export function EntrypointCmdInputs({ const watchImageTag = watch('image_tag') return ( - <> +
)} - + ) } diff --git a/libs/shared/routes/src/lib/sub-router/application.router.ts b/libs/shared/routes/src/lib/sub-router/application.router.ts index 8f5a4de6950..4031a5d1649 100644 --- a/libs/shared/routes/src/lib/sub-router/application.router.ts +++ b/libs/shared/routes/src/lib/sub-router/application.router.ts @@ -13,7 +13,6 @@ export const APPLICATION_MONITORING_GENERAL_URL = '/dashboard' export const APPLICATION_SETTINGS_GENERAL_URL = '/general' export const APPLICATION_SETTINGS_RESOURCES_URL = '/resources' -export const APPLICATION_SETTINGS_CONFIGURE_URL = '/configure' export const APPLICATION_SETTINGS_DOCKERFILE_URL = '/dockerfile' export const APPLICATION_SETTINGS_VALUES_OVERRIDE_FILE_URL = '/values-override-file' export const APPLICATION_SETTINGS_VALUES_OVERRIDE_ARGUMENTS_URL = '/values-override-arguments' diff --git a/libs/shared/ui/src/lib/components/enable-box/enable-box.tsx b/libs/shared/ui/src/lib/components/enable-box/enable-box.tsx index 8a1813e5570..5a694c9cd06 100644 --- a/libs/shared/ui/src/lib/components/enable-box/enable-box.tsx +++ b/libs/shared/ui/src/lib/components/enable-box/enable-box.tsx @@ -56,7 +56,7 @@ export function EnableBox(props: EnableBoxProps) { {title} - {description &&

{description}

} + {description &&

{description}

} {currentChecked &&
e.stopPropagation()}>{children}
}