From b5e189d88d23c09a6e71ff0c6b708be6a0cfe026 Mon Sep 17 00:00:00 2001 From: Shreerang Kale Date: Tue, 22 Oct 2024 19:10:53 +0530 Subject: [PATCH 1/7] Navigate to success page after deployment status is ready --- .../src/components/projects/create/Deploy.tsx | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/frontend/src/components/projects/create/Deploy.tsx b/packages/frontend/src/components/projects/create/Deploy.tsx index e943dfed..9e3bfd8d 100644 --- a/packages/frontend/src/components/projects/create/Deploy.tsx +++ b/packages/frontend/src/components/projects/create/Deploy.tsx @@ -1,5 +1,6 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; +import { Deployment, DeploymentStatus } from 'gql-client'; import { DeployStep, DeployStatus } from './DeployStep'; import { Stopwatch, setStopWatchOffset } from '../../StopWatch'; @@ -7,13 +8,19 @@ import { Heading } from '../../shared/Heading'; import { Button } from '../../shared/Button'; import { ClockOutlineIcon, WarningIcon } from '../../shared/CustomIcon'; import { CancelDeploymentDialog } from '../../projects/Dialog/CancelDeploymentDialog'; +import { useGQLClient } from 'context/GQLClientContext'; + +const FETCH_DEPLOYMENTS_INTERVAL = 5000; -const TIMEOUT_DURATION = 5000; const Deploy = () => { + const client = useGQLClient(); + const [searchParams] = useSearchParams(); const projectId = searchParams.get('projectId'); const [open, setOpen] = React.useState(false); + const [deployments, setDeployments] = useState([]); + const handleOpen = () => setOpen(!open); const navigate = useNavigate(); @@ -23,13 +30,35 @@ const Deploy = () => { navigate(`/${orgSlug}/projects/create`); }, []); - useEffect(() => { - const timerID = setTimeout(() => { - navigate(`/${orgSlug}/projects/create/success/${projectId}`); - }, TIMEOUT_DURATION); + const fetchDeployments = useCallback(async () => { + if (!projectId) { + return; + } - return () => clearInterval(timerID); - }, []); + const { deployments } = await client.getDeployments(projectId); + setDeployments(deployments); + }, [client, projectId]); + + useEffect(() => { + fetchDeployments(); + + const interval = setInterval(() => { + fetchDeployments(); + }, FETCH_DEPLOYMENTS_INTERVAL); + + return () => { + clearInterval(interval); + }; + }, [fetchDeployments]); + + useEffect(() => { + if ( + deployments.length > 0 && + deployments[0].status === DeploymentStatus.Ready + ) { + navigate(`/${orgSlug}/projects/create/success/${projectId}`); + } + }, [deployments]); return (
-- 2.45.2 From 1c13bcf66d233c4e2cf2583771ce0760303f9c0e Mon Sep 17 00:00:00 2001 From: Shreerang Kale Date: Wed, 23 Oct 2024 14:56:34 +0530 Subject: [PATCH 2/7] Check for deployment status while creating project using deployer API --- .../backend/environments/local.toml.example | 10 -- .../src/components/projects/create/Deploy.tsx | 159 +++++++++++++----- .../components/projects/create/DeployStep.tsx | 82 +-------- 3 files changed, 118 insertions(+), 133 deletions(-) diff --git a/packages/backend/environments/local.toml.example b/packages/backend/environments/local.toml.example index 2c8eca54..efebff59 100644 --- a/packages/backend/environments/local.toml.example +++ b/packages/backend/environments/local.toml.example @@ -20,16 +20,6 @@ clientId = "" clientSecret = "" -[google] - clientId = "" - clientSecret = "" - -[turnkey] - apiBaseUrl = "https://api.turnkey.com" - apiPrivateKey = "" - apiPublicKey = "" - defaultOrganizationId = "" - [registryConfig] fetchDeploymentRecordDelay = 5000 checkAuctionStatusDelay = 5000 diff --git a/packages/frontend/src/components/projects/create/Deploy.tsx b/packages/frontend/src/components/projects/create/Deploy.tsx index 9e3bfd8d..4fb25c69 100644 --- a/packages/frontend/src/components/projects/create/Deploy.tsx +++ b/packages/frontend/src/components/projects/create/Deploy.tsx @@ -1,6 +1,5 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; -import { Deployment, DeploymentStatus } from 'gql-client'; import { DeployStep, DeployStatus } from './DeployStep'; import { Stopwatch, setStopWatchOffset } from '../../StopWatch'; @@ -12,6 +11,23 @@ import { useGQLClient } from 'context/GQLClientContext'; const FETCH_DEPLOYMENTS_INTERVAL = 5000; +type RequestState = + | 'SUBMITTED' + | 'DEPLOYING' + | 'DEPLOYED' + | 'REMOVED' + | 'CANCELLED' + | 'ERROR'; + +type Record = { + id: string; + createTime: string; + app: string; + lastState: RequestState; + lastUpdate: string; + logAvailable: boolean; +}; + const Deploy = () => { const client = useGQLClient(); @@ -19,7 +35,7 @@ const Deploy = () => { const projectId = searchParams.get('projectId'); const [open, setOpen] = React.useState(false); - const [deployments, setDeployments] = useState([]); + const [record, setRecord] = useState(); const handleOpen = () => setOpen(!open); @@ -30,35 +46,84 @@ const Deploy = () => { navigate(`/${orgSlug}/projects/create`); }, []); - const fetchDeployments = useCallback(async () => { + const showSteps = useMemo(() => { + if (!record) { + return true; + } + + if ( + record.lastState === 'CANCELLED' || + record.lastState === 'REMOVED' || + record.lastState === 'ERROR' + ) { + return false; + } else { + return true; + } + }, [record]); + + const showTimer = useMemo(() => { + if (!record) { + return true; + } + + if ( + record.lastState === 'CANCELLED' || + record.lastState === 'REMOVED' || + record.lastState === 'ERROR' || + record.lastState === 'DEPLOYED' + ) { + return false; + } else { + return true; + } + }, [record]); + + const fetchDeploymentRecords = useCallback(async () => { if (!projectId) { return; } const { deployments } = await client.getDeployments(projectId); - setDeployments(deployments); + const deployment = deployments[0]; + + try { + const response = await fetch( + `${deployment.deployer.deployerApiUrl}/${deployment.applicationDeploymentRequestId}`, + ); + + if (!response.ok) { + throw new Error('Network response was not ok'); + } + + const record: Record = await response.json(); + setRecord(record); + } catch (err: any) { + console.log('Error fetching data from deployer', err); + } }, [client, projectId]); useEffect(() => { - fetchDeployments(); + fetchDeploymentRecords(); const interval = setInterval(() => { - fetchDeployments(); + fetchDeploymentRecords(); }, FETCH_DEPLOYMENTS_INTERVAL); return () => { clearInterval(interval); }; - }, [fetchDeployments]); + }, [fetchDeploymentRecords]); useEffect(() => { - if ( - deployments.length > 0 && - deployments[0].status === DeploymentStatus.Ready - ) { + if (!record) { + return; + } + + if (record.lastState === 'DEPLOYED') { navigate(`/${orgSlug}/projects/create/success/${projectId}`); } - }, [deployments]); + }, [record]); return (
@@ -67,12 +132,14 @@ const Deploy = () => { Deployment started ... -
- - -
+ {showTimer && ( +
+ + +
+ )}
-
- - - - -
+ {showSteps ? ( +
+ + + +
+ ) : ( +
+ +
+ )} ); }; diff --git a/packages/frontend/src/components/projects/create/DeployStep.tsx b/packages/frontend/src/components/projects/create/DeployStep.tsx index 2453b7ee..b797ae5d 100644 --- a/packages/frontend/src/components/projects/create/DeployStep.tsx +++ b/packages/frontend/src/components/projects/create/DeployStep.tsx @@ -1,27 +1,16 @@ -import { useState } from 'react'; - -import { Collapse } from '@snowballtools/material-tailwind-react-fork'; - import { Stopwatch, setStopWatchOffset } from '../../StopWatch'; -import FormatMillisecond from '../../FormatMilliSecond'; -import processLogs from '../../../assets/process-logs.json'; import { cn } from 'utils/classnames'; import { CheckRoundFilledIcon, ClockOutlineIcon, - CopyIcon, LoaderIcon, - MinusCircleIcon, - PlusIcon, } from 'components/shared/CustomIcon'; -import { Button } from 'components/shared/Button'; -import { useToast } from 'components/shared/Toast'; -import { useIntersectionObserver } from 'usehooks-ts'; enum DeployStatus { PROCESSING = 'progress', COMPLETE = 'complete', NOT_STARTED = 'notStarted', + ERROR = 'error', } interface DeployStepsProps { @@ -37,30 +26,11 @@ const DeployStep = ({ status, title, startTime, - processTime, }: DeployStepsProps) => { - const [isOpen, setIsOpen] = useState(false); - const { toast, dismiss } = useToast(); - const { isIntersecting: hideGradientOverlay, ref } = useIntersectionObserver({ - threshold: 1, - }); - - const disableCollapse = status !== DeployStatus.COMPLETE; - return (
- {/* Collapisble trigger */}
- {' '} )} - - {/* Collapsible */} - -
- {/* Logs */} - {processLogs.map((log, key) => { - return ( -

- {log} -

- ); - })} - - {/* End of logs ref used for hiding gradient overlay */} -
- - {/* Overflow gradient overlay */} - {!hideGradientOverlay && ( -
- )} - - {/* Copy log button */} -
- -
-
-
); }; -- 2.45.2 From 7a226dfbfd5cdd471e0ec1104f8ba557d0c0fe4e Mon Sep 17 00:00:00 2001 From: Shreerang Kale Date: Wed, 23 Oct 2024 15:59:47 +0530 Subject: [PATCH 3/7] Remove checking for REMOVED deployment status --- .../frontend/src/components/projects/create/Deploy.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/frontend/src/components/projects/create/Deploy.tsx b/packages/frontend/src/components/projects/create/Deploy.tsx index 4fb25c69..9acfdff8 100644 --- a/packages/frontend/src/components/projects/create/Deploy.tsx +++ b/packages/frontend/src/components/projects/create/Deploy.tsx @@ -51,11 +51,8 @@ const Deploy = () => { return true; } - if ( - record.lastState === 'CANCELLED' || - record.lastState === 'REMOVED' || - record.lastState === 'ERROR' - ) { + // Not checking for `REMOVED` status as this status is received for a brief period before receiving `DEPLOYED` status + if (record.lastState === 'CANCELLED' || record.lastState === 'ERROR') { return false; } else { return true; @@ -67,9 +64,9 @@ const Deploy = () => { return true; } + // Not checking for `REMOVED` status as this status is received for a brief period before receiving `DEPLOYED` status if ( record.lastState === 'CANCELLED' || - record.lastState === 'REMOVED' || record.lastState === 'ERROR' || record.lastState === 'DEPLOYED' ) { -- 2.45.2 From d96a7af22451dcedfa204de2c864198c1c31c1c5 Mon Sep 17 00:00:00 2001 From: Shreerang Kale Date: Thu, 24 Oct 2024 10:06:10 +0530 Subject: [PATCH 4/7] Stop timer if deployment failed --- .../frontend/src/components/StopWatch.tsx | 12 ++- .../src/components/projects/create/Deploy.tsx | 80 ++++++++----------- .../components/projects/create/DeployStep.tsx | 2 +- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/packages/frontend/src/components/StopWatch.tsx b/packages/frontend/src/components/StopWatch.tsx index d9c62775..fb512e24 100644 --- a/packages/frontend/src/components/StopWatch.tsx +++ b/packages/frontend/src/components/StopWatch.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import { useStopwatch } from 'react-timer-hook'; import FormatMillisecond, { FormatMilliSecondProps } from './FormatMilliSecond'; @@ -12,14 +13,21 @@ const setStopWatchOffset = (time: string) => { interface StopwatchProps extends Omit { offsetTimestamp: Date; + isPaused: boolean; } -const Stopwatch = ({ offsetTimestamp, ...props }: StopwatchProps) => { - const { totalSeconds } = useStopwatch({ +const Stopwatch = ({ offsetTimestamp, isPaused, ...props }: StopwatchProps) => { + const { totalSeconds, pause } = useStopwatch({ autoStart: true, offsetTimestamp: offsetTimestamp, }); + useEffect(() => { + if (isPaused) { + pause(); + } + }, [isPaused]); + return ; }; diff --git a/packages/frontend/src/components/projects/create/Deploy.tsx b/packages/frontend/src/components/projects/create/Deploy.tsx index 9acfdff8..3bf8ac13 100644 --- a/packages/frontend/src/components/projects/create/Deploy.tsx +++ b/packages/frontend/src/components/projects/create/Deploy.tsx @@ -1,5 +1,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; +import axios from 'axios'; +import { Deployment } from 'gql-client'; import { DeployStep, DeployStatus } from './DeployStep'; import { Stopwatch, setStopWatchOffset } from '../../StopWatch'; @@ -35,6 +37,7 @@ const Deploy = () => { const projectId = searchParams.get('projectId'); const [open, setOpen] = React.useState(false); + const [deployment, setDeployment] = useState(); const [record, setRecord] = useState(); const handleOpen = () => setOpen(!open); @@ -46,61 +49,47 @@ const Deploy = () => { navigate(`/${orgSlug}/projects/create`); }, []); - const showSteps = useMemo(() => { + const isDeploymentFailed = useMemo(() => { if (!record) { - return true; + return false; } // Not checking for `REMOVED` status as this status is received for a brief period before receiving `DEPLOYED` status if (record.lastState === 'CANCELLED' || record.lastState === 'ERROR') { - return false; + return true; } else { - return true; - } - }, [record]); - - const showTimer = useMemo(() => { - if (!record) { - return true; - } - - // Not checking for `REMOVED` status as this status is received for a brief period before receiving `DEPLOYED` status - if ( - record.lastState === 'CANCELLED' || - record.lastState === 'ERROR' || - record.lastState === 'DEPLOYED' - ) { return false; - } else { - return true; } }, [record]); const fetchDeploymentRecords = useCallback(async () => { + if (!deployment) { + return; + } + + try { + const response = await axios.get( + `${deployment.deployer.deployerApiUrl}/${deployment.applicationDeploymentRequestId}`, + ); + + const record: Record = response.data; + setRecord(record); + } catch (err: any) { + console.log('Error fetching data from deployer', err); + } + }, [deployment]); + + const fetchDeployment = useCallback(async () => { if (!projectId) { return; } const { deployments } = await client.getDeployments(projectId); - const deployment = deployments[0]; - - try { - const response = await fetch( - `${deployment.deployer.deployerApiUrl}/${deployment.applicationDeploymentRequestId}`, - ); - - if (!response.ok) { - throw new Error('Network response was not ok'); - } - - const record: Record = await response.json(); - setRecord(record); - } catch (err: any) { - console.log('Error fetching data from deployer', err); - } + setDeployment(deployments[0]); }, [client, projectId]); useEffect(() => { + fetchDeployment(); fetchDeploymentRecords(); const interval = setInterval(() => { @@ -110,7 +99,7 @@ const Deploy = () => { return () => { clearInterval(interval); }; - }, [fetchDeploymentRecords]); + }, [fetchDeployment, fetchDeploymentRecords]); useEffect(() => { if (!record) { @@ -129,14 +118,13 @@ const Deploy = () => { Deployment started ... - {showTimer && ( -
- - -
- )} +
+ + +