Skip to content

Commit

Permalink
feat(page-new-services): add page and update service creation flow (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
RemiBonnet authored May 17, 2024
1 parent 762e43d commit a152a03
Show file tree
Hide file tree
Showing 41 changed files with 1,800 additions and 141 deletions.
4 changes: 1 addition & 3 deletions apps/console/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ export function App() {

useEffect(() => {
if (user && user.sub) {
if (NODE_ENV === 'production') {
initMonitorings(user)
}
initMonitorings(user)
}
}, [user, initMonitorings])

Expand Down
28 changes: 28 additions & 0 deletions apps/console/src/app/router/main.router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@ import {
ORGANIZATION_URL,
OVERVIEW_URL,
SERVICES_APPLICATION_CREATION_URL,
SERVICES_APPLICATION_TEMPLATE_CREATION_URL,
SERVICES_CRONJOB_CREATION_URL,
SERVICES_DATABASE_CREATION_URL,
SERVICES_DATABASE_TEMPLATE_CREATION_URL,
SERVICES_HELM_CREATION_URL,
SERVICES_HELM_TEMPLATE_CREATION_URL,
SERVICES_LIFECYCLE_CREATION_URL,
SERVICES_LIFECYCLE_TEMPLATE_CREATION_URL,
SERVICES_URL,
SETTINGS_URL,
USER_URL,
Expand Down Expand Up @@ -125,6 +129,12 @@ export const ROUTER: RouterProps[] = [
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_DATABASE_TEMPLATE_CREATION_URL()}/*`,
component: <PageDatabaseCreateFeature />,
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_CRONJOB_CREATION_URL}/*`,
component: <PageJobCreateFeature />,
Expand All @@ -137,18 +147,36 @@ export const ROUTER: RouterProps[] = [
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_LIFECYCLE_TEMPLATE_CREATION_URL()}/*`,
component: <PageJobCreateFeature />,
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_APPLICATION_CREATION_URL}/*`,
component: <PageApplicationCreateFeature />,
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_APPLICATION_TEMPLATE_CREATION_URL()}/*`,
component: <PageApplicationCreateFeature />,
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_HELM_CREATION_URL}/*`,
component: <PageHelmCreateFeature />,
protected: true,
layout: false,
},
{
path: `${SERVICES_URL()}${SERVICES_HELM_TEMPLATE_CREATION_URL()}/*`,
component: <PageHelmCreateFeature />,
protected: true,
layout: false,
},
{
path: `${APPLICATION_URL()}/*`,
component: <PageApplication />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ exports[`AnnotationItemsListModal should match snapshots 1`] = `
role="img"
/>
<input
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 leading-none focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
data-testid="input-search"
name="search"
placeholder="Search by project, environment, service name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ exports[`GitTokenServicesListModal should match snapshots 1`] = `
role="img"
/>
<input
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 leading-none focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
data-testid="input-search"
name="search"
placeholder="Search by project, environment, service name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ exports[`SelectCommitModal should match snapshot 1`] = `
For X service
</div>
<div
class="relative w-full "
class="relative w-full"
>
<span
class="icon-solid-magnifying-glass shrink-0 absolute left-3 top-1/2 -translate-y-1/2 block text-base text-neutral-400 dark:text-white leading-none"
role="img"
/>
<input
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 leading-none focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
class="w-full rounded border border-neutral-250 dark:border-neutral-350 dark:bg-transparent text-neutral-400 dark:text-white placeholder:text-neutral-350 dark:placeholder:text-neutral-250 pl-10 pr-6 focus:outline-none focus:border-brand-400 focus:transition-[border-color] h-9 text-xs"
data-testid="input-search"
name="search"
placeholder="Search by commit message or commit id"
Expand Down Expand Up @@ -73,7 +73,7 @@ exports[`SelectCommitModal should match snapshot 1`] = `
<div>
<button
aria-checked="false"
class="group transition bg-neutral-100 border border-neutral-300 w-[20px] h-[20px] rounded-full hover:border-2 hover:border-brand-500 data-[state=checked]:bg-brand-500 data-[state=checked]:border-brand-500 disabled:hover:border disabled:bg-neutral-150 disabled:border-neutral-250 disabled:data-[state=checked]:hover:border-2 disabled:data-[state=checked]:border-brand-300 disabled:data-[state=checked]:bg-brand-300"
class="group transition bg-neutral-100 border border-neutral-300 w-[20px] h-[20px] rounded-full hover:border-2 hover:border-brand-500 data-[state=checked]:bg-brand-500 data-[state=checked]:border-2 data-[state=checked]:border-brand-500 disabled:hover:border disabled:bg-neutral-150 disabled:border-neutral-250 disabled:data-[state=checked]:hover:border-2 disabled:data-[state=checked]:border-brand-300 disabled:data-[state=checked]:bg-brand-300"
data-radix-collection-item=""
data-state="unchecked"
role="radio"
Expand Down Expand Up @@ -175,7 +175,7 @@ exports[`SelectCommitModal should match snapshot 1`] = `
<div>
<button
aria-checked="true"
class="group transition bg-neutral-100 border border-neutral-300 w-[20px] h-[20px] rounded-full hover:border-2 hover:border-brand-500 data-[state=checked]:bg-brand-500 data-[state=checked]:border-brand-500 disabled:hover:border disabled:bg-neutral-150 disabled:border-neutral-250 disabled:data-[state=checked]:hover:border-2 disabled:data-[state=checked]:border-brand-300 disabled:data-[state=checked]:bg-brand-300"
class="group transition bg-neutral-100 border border-neutral-300 w-[20px] h-[20px] rounded-full hover:border-2 hover:border-brand-500 data-[state=checked]:bg-brand-500 data-[state=checked]:border-2 data-[state=checked]:border-brand-500 disabled:hover:border disabled:bg-neutral-150 disabled:border-neutral-250 disabled:data-[state=checked]:hover:border-2 disabled:data-[state=checked]:border-brand-300 disabled:data-[state=checked]:bg-brand-300"
data-disabled=""
data-radix-collection-item=""
data-state="checked"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table'
import { PostHogFeature } from 'posthog-js/react'
import type {
ApplicationGitRepository,
ContainerResponse,
Expand All @@ -36,7 +37,14 @@ import {
DATABASE_URL,
DEPLOYMENT_LOGS_URL,
ENVIRONMENT_LOGS_URL,
SERVICES_APPLICATION_CREATION_URL,
SERVICES_CRONJOB_CREATION_URL,
SERVICES_DATABASE_CREATION_URL,
SERVICES_GENERAL_URL,
SERVICES_HELM_CREATION_URL,
SERVICES_LIFECYCLE_CREATION_URL,
SERVICES_NEW_URL,
SERVICES_URL,
} from '@qovery/shared/routes'
import {
Badge,
Expand All @@ -46,6 +54,9 @@ import {
ExternalLink,
Icon,
Link,
Menu,
MenuAlign,
type MenuData,
StatusChip,
TableFilter,
TablePrimitives,
Expand Down Expand Up @@ -525,6 +536,52 @@ export function ServiceList({ environment, className, ...props }: ServiceListPro
},
})

const newServicesMenu: MenuData = [
{
items: [
{
name: 'Create application',
contentLeft: <Icon iconName="layer-group" className="text-brand-500 text-sm" />,
onClick: () => {
navigate(`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_APPLICATION_CREATION_URL}`)
},
},
{
name: 'Create database',
contentLeft: <Icon iconName="database" className="text-brand-500 text-sm" />,
onClick: () => {
navigate(`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_DATABASE_CREATION_URL}`)
},
},
{
name: 'Create lifecycle job',
contentLeft: (
<Icon name={IconEnum.LIFECYCLE_JOB_STROKE} width="14" height="16" className="text-brand-500 text-sm" />
),
onClick: () => {
navigate(`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_LIFECYCLE_CREATION_URL}`)
},
},
{
name: 'Create cronjob',
contentLeft: (
<Icon name={IconEnum.CRON_JOB_STROKE} width="14" height="16" className="text-brand-500 text-sm" />
),
onClick: () => {
navigate(`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_CRONJOB_CREATION_URL}`)
},
},
{
name: 'Create helm',
contentLeft: <Icon name={IconEnum.HELM_OFFICIAL} width="14" height="16" className="text-brand-500 text-sm" />,
onClick: () => {
navigate(`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_HELM_CREATION_URL}`)
},
},
],
},
]

if (services.length === 0 && isServicesLoading) {
return <ServiceListSkeleton />
}
Expand All @@ -535,7 +592,34 @@ export function ServiceList({ environment, className, ...props }: ServiceListPro
title="No service found"
description="You can create a service from the button on the top"
className="bg-white rounded-t-sm mt-2 pt-10"
/>
>
<PostHogFeature
flag="service-template"
match={true}
fallback={
<Menu
trigger={
<Button size="lg" className="gap-2 mt-5">
New service
<Icon iconName="circle-plus" />
</Button>
}
menus={newServicesMenu}
arrowAlign={MenuAlign.CENTER}
/>
}
>
<Link
as="button"
size="lg"
className="gap-2 mt-5"
to={`${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_NEW_URL}`}
>
New service
<Icon iconName="circle-plus" />
</Link>
</PostHogFeature>
</EmptyState>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useFeatureFlagEnabled } from 'posthog-js/react'
import { createContext, useContext, useState } from 'react'
import { Navigate, Route, Routes, useNavigate, useParams } from 'react-router-dom'
import { AssistantTrigger } from '@qovery/shared/assistant/feature'
Expand All @@ -6,7 +7,13 @@ import {
type ApplicationResourcesData,
type FlowPortData,
} from '@qovery/shared/interfaces'
import { SERVICES_APPLICATION_CREATION_URL, SERVICES_CREATION_GENERAL_URL, SERVICES_URL } from '@qovery/shared/routes'
import {
SERVICES_APPLICATION_CREATION_URL,
SERVICES_CREATION_GENERAL_URL,
SERVICES_GENERAL_URL,
SERVICES_NEW_URL,
SERVICES_URL,
} from '@qovery/shared/routes'
import { FunnelFlow } from '@qovery/shared/ui'
import { useDocumentTitle } from '@qovery/shared/util-hooks'
import { ROUTER_SERVICE_CREATION } from '../../router/router'
Expand Down Expand Up @@ -43,7 +50,7 @@ export const steps: { title: string }[] = [
]

export function PageApplicationCreateFeature() {
const { organizationId = '', projectId = '', environmentId = '' } = useParams()
const { organizationId = '', projectId = '', environmentId = '', slug, option } = useParams()

// values and setters for context initialization
const [currentStep, setCurrentStep] = useState<number>(1)
Expand All @@ -64,7 +71,12 @@ export function PageApplicationCreateFeature() {

useDocumentTitle('Creation - Service')

const pathCreate = `${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_APPLICATION_CREATION_URL}`
const pathCreate =
SERVICES_URL(organizationId, projectId, environmentId) +
SERVICES_APPLICATION_CREATION_URL +
`${slug && option ? `/${slug}/${option}` : ''}`

const flagEnabled = useFeatureFlagEnabled('service-template')

return (
<ApplicationContainerCreateContext.Provider
Expand All @@ -81,7 +93,10 @@ export function PageApplicationCreateFeature() {
>
<FunnelFlow
onExit={() => {
navigate(SERVICES_URL(organizationId, projectId, environmentId))
const link = `${SERVICES_URL(organizationId, projectId, environmentId)}${
flagEnabled ? SERVICES_NEW_URL : SERVICES_GENERAL_URL
}`
navigate(link)
}}
totalSteps={steps.length}
currentStep={currentStep}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,37 @@ import { useEffect } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { useNavigate, useParams } from 'react-router-dom'
import { useOrganization } from '@qovery/domains/organizations/feature'
import { type ServiceTypeEnum } from '@qovery/shared/enums'
import { type ApplicationGeneralData } from '@qovery/shared/interfaces'
import { SERVICES_APPLICATION_CREATION_URL, SERVICES_CREATION_RESOURCES_URL, SERVICES_URL } from '@qovery/shared/routes'
import { FunnelFlowBody, toastError } from '@qovery/shared/ui'
import { useDocumentTitle } from '@qovery/shared/util-hooks'
import StepGeneral from '../../../ui/page-application-create/step-general/step-general'
import { findTemplateData } from '../../page-job-create-feature/page-job-create-feature'
import { serviceTemplates } from '../../page-new-feature/service-templates'
import { useApplicationContainerCreateContext } from '../page-application-create-feature'

export function StepGeneralFeature() {
useDocumentTitle('General - Create Application')
const { setGeneralData, generalData, setCurrentStep } = useApplicationContainerCreateContext()
const { organizationId = '', projectId = '', environmentId = '' } = useParams()
const { organizationId = '', projectId = '', environmentId = '', slug, option } = useParams()
const navigate = useNavigate()
const { data: organization } = useOrganization({ organizationId })

useEffect(() => {
setCurrentStep(1)
}, [setCurrentStep])

const dataTemplate = serviceTemplates.find((service) => service.slug === slug)
const dataOptionTemplate = option !== 'current' ? findTemplateData(slug, option) : null

const methods = useForm<ApplicationGeneralData>({
defaultValues: { auto_deploy: true, ...generalData },
defaultValues: {
auto_deploy: true,
name: dataTemplate?.slug ?? '',
serviceType: (dataOptionTemplate?.type as ServiceTypeEnum) ?? (dataTemplate?.type as ServiceTypeEnum),
...generalData,
},
mode: 'onChange',
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import posthog from 'posthog-js'
import {
type ApplicationRequest,
BuildModeEnum,
Expand Down Expand Up @@ -26,7 +27,7 @@ export function StepSummaryFeature() {
useDocumentTitle('Summary - Create Application')
const { generalData, portData, resourcesData, setCurrentStep } = useApplicationContainerCreateContext()
const navigate = useNavigate()
const { organizationId = '', projectId = '', environmentId = '' } = useParams()
const { organizationId = '', projectId = '', environmentId = '', slug, option } = useParams()
const pathCreate = `${SERVICES_URL(organizationId, projectId, environmentId)}${SERVICES_APPLICATION_CREATION_URL}`
const [loadingCreate, setLoadingCreate] = useState(false)
const [loadingCreateAndDeploy, setLoadingCreateAndDeploy] = useState(false)
Expand Down Expand Up @@ -127,6 +128,14 @@ export function StepSummaryFeature() {
})
setLoadingCreateAndDeploy(false)
}

if (slug && option) {
posthog.capture('create-service', {
selectedServiceType: slug,
selectedServiceSubType: option,
})
}

setLoadingCreate(false)
navigate(SERVICES_URL(organizationId, projectId, environmentId))
} catch (error) {
Expand Down
Loading

0 comments on commit a152a03

Please sign in to comment.