From c4fc8855e1d95eff50b4357dbabafbb7b2478be1 Mon Sep 17 00:00:00 2001 From: bdebon Date: Mon, 26 Dec 2022 18:13:06 +0100 Subject: [PATCH] fix(jobs): various bugs (#430) * overview job displaying git card or container * design of summary page * variable row creation funnel --- .../last-commit-feature.tsx | 31 +++- .../about-content-container.spec.tsx | 16 ++ .../about-content-container.tsx | 31 ++++ .../src/lib/ui/page-general/page-general.tsx | 27 +-- .../page-job-create-feature.tsx | 1 - .../step-summary/step-summary.tsx | 173 +++++++++++++----- .../ui/variable-row/variable-row.tsx | 7 +- .../input-text-small/input-text-small.tsx | 4 +- 8 files changed, 211 insertions(+), 79 deletions(-) create mode 100644 libs/pages/application/src/lib/ui/about-content-container/about-content-container.spec.tsx create mode 100644 libs/pages/application/src/lib/ui/about-content-container/about-content-container.tsx diff --git a/libs/pages/application/src/lib/feature/last-commit-feature/last-commit-feature.tsx b/libs/pages/application/src/lib/feature/last-commit-feature/last-commit-feature.tsx index df954e11fb..af69db58d9 100644 --- a/libs/pages/application/src/lib/feature/last-commit-feature/last-commit-feature.tsx +++ b/libs/pages/application/src/lib/feature/last-commit-feature/last-commit-feature.tsx @@ -2,7 +2,8 @@ import { Commit } from 'qovery-typescript-axios' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { getApplicationsState, getCountNewCommitsToDeploy } from '@qovery/domains/application' -import { GitApplicationEntity } from '@qovery/shared/interfaces' +import { isJob } from '@qovery/shared/enums' +import { GitApplicationEntity, JobApplicationEntity, LoadingStatus } from '@qovery/shared/interfaces' import { RootState } from '@qovery/store' import LastCommit from '../../ui/last-commit/last-commit' @@ -13,22 +14,36 @@ export function LastCommitFeature() { (state) => getApplicationsState(state).entities[applicationId] ) - const getCommitById = (commits: Commit[]) => { - const deployedCommit = commits.find( - (commit) => commit.git_commit_id === application?.git_repository?.deployed_commit_id - ) + const getCommitById = (commits?: Commit[]) => { + const deployedCommitId = isJob(application) + ? (application as JobApplicationEntity).source?.docker?.git_repository?.deployed_commit_id + : application?.git_repository?.deployed_commit_id + + const deployedCommit = commits?.find((commit) => commit.git_commit_id === deployedCommitId) if (deployedCommit) { return deployedCommit } else { - return application?.git_repository + return isJob(application) + ? (application as JobApplicationEntity).source?.docker?.git_repository + : application?.git_repository + } + } + + const loadingStatus = (): LoadingStatus => { + if (!application) { + return 'loading' + } + if (isJob(application)) { + return 'loaded' } + return application?.commits?.loadingStatus } return ( ) diff --git a/libs/pages/application/src/lib/ui/about-content-container/about-content-container.spec.tsx b/libs/pages/application/src/lib/ui/about-content-container/about-content-container.spec.tsx new file mode 100644 index 0000000000..ba2b3275b9 --- /dev/null +++ b/libs/pages/application/src/lib/ui/about-content-container/about-content-container.spec.tsx @@ -0,0 +1,16 @@ +import { render } from '__tests__/utils/setup-jest' +import { applicationFactoryMock } from '@qovery/domains/application' +import { ContainerApplicationEntity } from '@qovery/shared/interfaces' +import AboutContentContainer, { AboutContentContainerProps } from './about-content-container' + +const mockApplication = applicationFactoryMock(1)[0] +const props: AboutContentContainerProps = { + application: mockApplication as ContainerApplicationEntity, +} + +describe('AboutContentContainer', () => { + it('should render successfully', () => { + const { baseElement } = render() + expect(baseElement).toBeTruthy() + }) +}) diff --git a/libs/pages/application/src/lib/ui/about-content-container/about-content-container.tsx b/libs/pages/application/src/lib/ui/about-content-container/about-content-container.tsx new file mode 100644 index 0000000000..f927e8cf3e --- /dev/null +++ b/libs/pages/application/src/lib/ui/about-content-container/about-content-container.tsx @@ -0,0 +1,31 @@ +import { ContainerApplicationEntity, JobApplicationEntity } from '@qovery/shared/interfaces' +import { timeAgo } from '@qovery/shared/utils' + +export interface AboutContentContainerProps { + application: ContainerApplicationEntity | JobApplicationEntity +} + +export function AboutContentContainer(props: AboutContentContainerProps) { + const { application } = props + + return ( +
+
Image information
+
+

+ Image name: {(application as ContainerApplicationEntity).image_name}{' '} + {(application as JobApplicationEntity).source?.image?.image_name} +

+

+ Latest deployed tag: {(application as ContainerApplicationEntity).tag}{' '} + {(application as JobApplicationEntity).source?.image?.tag} +

+

+ {timeAgo(new Date((application as ContainerApplicationEntity)?.updated_at || ''))} +

+
+
+ ) +} + +export default AboutContentContainer diff --git a/libs/pages/application/src/lib/ui/page-general/page-general.tsx b/libs/pages/application/src/lib/ui/page-general/page-general.tsx index b49ae2f274..d63d4e7a18 100644 --- a/libs/pages/application/src/lib/ui/page-general/page-general.tsx +++ b/libs/pages/application/src/lib/ui/page-general/page-general.tsx @@ -1,4 +1,4 @@ -import { getServiceType, isApplication } from '@qovery/shared/enums' +import { getServiceType, isApplication, isJob } from '@qovery/shared/enums' import { ContainerApplicationEntity, GitApplicationEntity, @@ -7,8 +7,8 @@ import { LoadingStatus, } from '@qovery/shared/interfaces' import { BaseLink, HelpSection, Icon, Skeleton, Tooltip } from '@qovery/shared/ui' -import { timeAgo } from '@qovery/shared/utils' import LastCommitFeature from '../../feature/last-commit-feature/last-commit-feature' +import AboutContentContainer from '../about-content-container/about-content-container' import About from '../about/about' import InstancesTable from '../instances-table/instances-table' @@ -87,23 +87,14 @@ export function PageGeneral(props: PageGeneralProps) { {application && (isApplication(application) ? ( + ) : isJob(application) ? ( + (application as JobApplicationEntity).source?.docker ? ( + + ) : ( + + ) ) : ( -
-
Image information
-
-

- Image name: {(application as ContainerApplicationEntity).image_name}{' '} - {(application as JobApplicationEntity).source?.image?.image_name} -

-

- Latest deployed tag: {(application as ContainerApplicationEntity).tag}{' '} - {(application as JobApplicationEntity).source?.image?.tag} -

-

- {timeAgo(new Date((application as ContainerApplicationEntity)?.updated_at || ''))} -

-
-
+ ))} diff --git a/libs/pages/services/src/lib/feature/page-job-create-feature/page-job-create-feature.tsx b/libs/pages/services/src/lib/feature/page-job-create-feature/page-job-create-feature.tsx index f969ffc143..e420bf1005 100644 --- a/libs/pages/services/src/lib/feature/page-job-create-feature/page-job-create-feature.tsx +++ b/libs/pages/services/src/lib/feature/page-job-create-feature/page-job-create-feature.tsx @@ -45,7 +45,6 @@ export const steps: { title: string }[] = [ { title: 'Create new job' }, { title: 'Job Configuration' }, { title: 'Set resources' }, - { title: 'Set port' }, { title: 'Set variable environments' }, { title: 'Ready to install' }, ] diff --git a/libs/pages/services/src/lib/ui/page-job-create/step-summary/step-summary.tsx b/libs/pages/services/src/lib/ui/page-job-create/step-summary/step-summary.tsx index 208f340918..86f0fc7cb7 100644 --- a/libs/pages/services/src/lib/ui/page-job-create/step-summary/step-summary.tsx +++ b/libs/pages/services/src/lib/ui/page-job-create/step-summary/step-summary.tsx @@ -1,5 +1,5 @@ import { BuildModeEnum } from 'qovery-typescript-axios' -import { JobType, ServiceTypeEnum } from '@qovery/shared/enums' +import { JobType, ServiceTypeEnum, isCronJob } from '@qovery/shared/enums' import { FlowVariableData, JobConfigureData, JobGeneralData, JobResourcesData } from '@qovery/shared/interfaces' import { Button, ButtonIcon, ButtonIconStyle, ButtonSize, ButtonStyle, Icon, IconAwesomeEnum } from '@qovery/shared/ui' @@ -25,7 +25,9 @@ export function StepSummary(props: StepSummaryProps) {
-

Ready to create your Cronjob

+

+ Ready to create your {isCronJob(props.jobType) ? 'Cron' : 'Lifecycle'} job +

The basic application setup is done, you can now deploy your application or move forward with some advanced @@ -42,36 +44,54 @@ export function StepSummary(props: StepSummaryProps) {

General
    -
  • {props.generalData.name}
  • -
  • {props.generalData.description}
  • +
  • + Name: {props.generalData.name} +
  • +
  • + Description: {props.generalData.description} +
{props.generalData.serviceType === ServiceTypeEnum.APPLICATION && ( <> -
- For application created from a Git provider -
    -
  • {props.generalData.repository}
  • -
  • {props.generalData.branch}
  • -
  • {props.generalData.root_path}
  • +
  • + Repository: {props.generalData.repository} +
  • +
  • + Branch: {props.generalData.branch} +
  • +
  • + Root path: {props.generalData.root_path} +
  • {props.generalData.build_mode === BuildModeEnum.DOCKER && ( -
  • {props.generalData.dockerfile_path}
  • +
  • + Dockerfile path: {props.generalData.dockerfile_path} +
  • )}
)} {props.generalData.serviceType === ServiceTypeEnum.CONTAINER && ( <> -
For application created from a Registry
    -
  • {props.selectedRegistryName}
  • -
  • Image name: {props.generalData.image_name}
  • -
  • Image tag: {props.generalData.image_tag}
  • -
  • Image entrypoint: {props.generalData.image_entry_point}
  • -
  • CMD arguments: {props.configureData.cmd_arguments}
  • +
  • + Registry: {props.selectedRegistryName} +
  • +
  • + Image name: {props.generalData.image_name} +
  • +
  • + Image tag: {props.generalData.image_tag} +
  • +
  • + Image entrypoint: {props.generalData.image_entry_point} +
  • +
  • + CMD arguments: {props.configureData.cmd_arguments} +
)} @@ -92,49 +112,102 @@ export function StepSummary(props: StepSummaryProps) { {props.jobType === ServiceTypeEnum.LIFECYCLE_JOB && ( <> -
Lifecycle job
+ {props.configureData.on_start?.enabled && ( + <> +
    +
  • +
    + EventsEnvironment Start +
    +
  • +
  • + Entrypoint:{' '} + {props.configureData.on_start?.entrypoint || 'null'} +
  • +
  • + CMD Arguments:{' '} + {props.configureData.on_start?.arguments || 'null'} +
  • +
+
+ + )} + {props.configureData.on_stop?.enabled && ( + <> +
    +
  • +
    + EventsEnvironment Stop +
    +
  • +
  • + Entrypoint:{' '} + {props.configureData.on_stop?.entrypoint || 'null'} +
  • +
  • + CMD Arguments:{' '} + {props.configureData.on_stop?.arguments || 'null'} +
  • +
+
+ + )} + {props.configureData.on_delete?.enabled && ( + <> +
    +
  • +
    + EventsEnvironment Delete +
    +
  • +
  • + Entrypoint:{' '} + {props.configureData.on_delete?.entrypoint || 'null'} +
  • +
  • + CMD Arguments:{' '} + {props.configureData.on_delete?.arguments || 'null'} +
  • +
+
+ + )} + + )} + + {props.jobType === ServiceTypeEnum.CRON_JOB && ( + <>
    - {props.configureData.on_start?.enabled && ( -
  • - On start – Entrypoint: {props.configureData.on_start?.entrypoint || 'null'} / CMD:{' '} - {props.configureData.on_start?.arguments || 'null'} -
  • - )} - {props.configureData.on_stop?.enabled && ( +
  • + Scheduled at: {props.configureData.schedule} +
  • + {props.configureData.image_entry_point && (
  • - On Stop – Entrypoint: {props.configureData.on_stop?.entrypoint || 'null'} / CMD:{' '} - {props.configureData.on_stop?.arguments || 'null'} + Entrypoint: {props.configureData.image_entry_point}
  • )} - {props.configureData.on_delete?.enabled && ( + {props.configureData.cmd_arguments && (
  • - On Delete – Entrypoint: {props.configureData.on_delete?.entrypoint || 'null'} / CMD:{' '} - {props.configureData.on_delete?.arguments || 'null'} + CMD arguments: {props.configureData.cmd_arguments}
  • )}
+
)} - {props.jobType === ServiceTypeEnum.CRON_JOB && ( - <> -
CRON
-
    -
  • {props.configureData.schedule}
  • - {props.configureData.image_entry_point &&
  • {props.configureData.image_entry_point}
  • } - {props.configureData.cmd_arguments &&
  • {props.configureData.cmd_arguments}
  • } -
- - )} - -
-
Parameters
    -
  • Max restarts: {props.configureData.nb_restarts}
  • -
  • Max duration: {props.configureData.max_duration}
  • -
  • Port: {props.configureData.port}
  • +
  • + Max restarts: {props.configureData.nb_restarts} +
  • +
  • + Max duration: {props.configureData.max_duration} +
  • +
  • + Port: {props.configureData.port} +
@@ -153,8 +226,12 @@ export function StepSummary(props: StepSummaryProps) {
Parameters
    -
  • CPU: {props.resourcesData['cpu'][0]}
  • -
  • Memory: {props.resourcesData.memory} MB
  • +
  • + CPU: {props.resourcesData['cpu'][0]} +
  • +
  • + Memory: {props.resourcesData.memory} MB +
diff --git a/libs/shared/console-shared/src/lib/flow-create-variable/ui/variable-row/variable-row.tsx b/libs/shared/console-shared/src/lib/flow-create-variable/ui/variable-row/variable-row.tsx index 2283a87603..18482f32cf 100644 --- a/libs/shared/console-shared/src/lib/flow-create-variable/ui/variable-row/variable-row.tsx +++ b/libs/shared/console-shared/src/lib/flow-create-variable/ui/variable-row/variable-row.tsx @@ -20,7 +20,8 @@ export interface VariableRowProps { export function VariableRow(props: VariableRowProps) { const { index, availableScopes, gridTemplateColumns = '6fr 6fr 204px 2fr 1fr 1fr' } = props - const { control, trigger } = useFormContext() + const { control, trigger, watch } = useFormContext() + const watchSecret = watch().variables[index]?.isSecret const pattern = /^[^\s]+$/ @@ -65,8 +66,8 @@ export function VariableRow(props: VariableRowProps) { value={field.value} error={error?.message} errorMessagePosition="left" - type="password" - hasShowPasswordButton={true} + type={watchSecret ? 'password' : 'text'} + hasShowPasswordButton={watchSecret} /> )} /> diff --git a/libs/shared/ui/src/lib/components/inputs/input-text-small/input-text-small.tsx b/libs/shared/ui/src/lib/components/inputs/input-text-small/input-text-small.tsx index f3592c7b7a..a205af26cf 100644 --- a/libs/shared/ui/src/lib/components/inputs/input-text-small/input-text-small.tsx +++ b/libs/shared/ui/src/lib/components/inputs/input-text-small/input-text-small.tsx @@ -57,7 +57,9 @@ export function InputTextSmall(props: InputTextSmallProps) { {props.label}