Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 111 additions & 24 deletions src/components/pages/deployments/_components/DeployLatest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import deployEnvironmentLatest from '@/lib/mutation/deployEnvironmentLatest';
import { useMutation } from '@apollo/client';
import { RefetchFunction } from '@apollo/client/react/hooks/useSuspenseQuery';
import { Button, Skeleton } from '@uselagoon/ui-library';
import { Loader2 } from 'lucide-react';
import { AlertCircle, GitBranch, Loader2, Zap } from 'lucide-react';
import { toast } from 'sonner';
import { useState } from 'react';

interface Props {
environment: DeploymentsData['environment'];
Expand All @@ -22,6 +23,8 @@ interface PropsWithSkeleton {
skeleton: true;
}

type DeploymentType = 'full' | 'variables';

const DeployLatestSkeleton = () => (
<section className="flex items-center gap-[1rem] mb-6 py-1.5">
<div className="description flex gap-2 items-center">
Expand All @@ -31,10 +34,51 @@ const DeployLatestSkeleton = () => (
</section>
);

interface DeployOptionCardProps {
selected: boolean;
onSelect: () => void;
icon: React.ReactNode;
title: string;
description: string;
disabled?: boolean;
}

const DeployOptionCard: React.FC<DeployOptionCardProps> = ({
selected,
onSelect,
icon,
title,
description,
disabled,
}) => (
<button
type="button"
onClick={onSelect}
disabled={disabled}
className={`
flex-1 flex items-start gap-3 p-4 rounded-lg border text-left transition-all
${selected
? 'border-blue-500 ring-1 ring-blue-500'
: 'border-gray-200 hover:border-gray-300 dark:border-gray-700 dark:hover:border-gray-600'
}
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
`}
>
<div className={`mt-0.5 ${selected ? 'text-blue-500' : 'text-gray-400'}`}>
{icon}
</div>
<div className="flex flex-col gap-1">
<span className="font-medium text-sm">{title}</span>
<span className="text-xs text-gray-500 dark:text-gray-400">{description}</span>
</div>
</button>
);

const DeployLatestData: React.FC<Props> = ({ environment }) => {
const { id, deployType, deployBaseRef, deployHeadRef, deployTitle } = environment;
const [selectedType, setSelectedType] = useState<DeploymentType>('full');

const [deployEnvironmentLatestMutation, { loading, error }] = useMutation(deployEnvironmentLatest, {
const [deployEnvironmentLatestMutation, { loading }] = useMutation(deployEnvironmentLatest, {
onError: err => {
console.error(err);
toast.error('Deployment error', {
Expand All @@ -44,9 +88,11 @@ const DeployLatestData: React.FC<Props> = ({ environment }) => {
},
variables: {
environmentId: id,
envVarOnly: selectedType === 'variables' ? "true" : "false",
},
onCompleted: () => {
toast.success('Deployment triggered');
const message = selectedType === 'variables' ? 'Variable-only deployment triggered' : 'Deployment triggered';
toast.success(message);
},
refetchQueries: ['getEnvironment'],
});
Expand All @@ -65,30 +111,71 @@ const DeployLatestData: React.FC<Props> = ({ environment }) => {
deploymentsEnabled = false;
}

if (!deploymentsEnabled) {
return (
<section className="flex items-center gap-[1rem] mb-6 w-max py-1.5">
<div className="description text-sm leading-[1.375rem]">
Manual deployments are not available for this environment.
</div>
<Button data-cy="deploy-button" disabled>
Deploy
</Button>
</section>
);
}

return (
<section className="flex items-center gap-[1rem] mb-6 w-max py-1.5">
{!deploymentsEnabled ? (
<>
<div className="description text-sm leading-[1.375rem]">
Manual deployments are not available for this environment.
</div>
<Button data-cy="deploy-button" disabled>
Deploy
</Button>
</>
) : (
<>
<div className="description text-sm leading-[1.375rem] flex gap-1 items-center">
{deployType === 'branch' && `Start a new deployment of branch ${deployBaseRef}.`}
{deployType === 'pullrequest' && `Start a new deployment of pull request ${deployTitle}.`}
{deployType === 'promote' &&
`Start a new deployment from environment ${environment.project.name}-${deployBaseRef}.`}
<section className="py-4 px-[18px] rounded-lg border mb-6">
<div className="mb-4">
<h3 className="text-base font-medium">Deployment Type</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">Choose how you want to deploy these changes</p>
</div>

<div className="flex gap-4">
<DeployOptionCard
selected={selectedType === 'full'}
onSelect={() => setSelectedType('full')}
icon={<GitBranch size={20} />}
title="Full Deployment"
description="Builds new images and applies all pending changes including variables, routes, and services."
disabled={loading}
/>
<DeployOptionCard
selected={selectedType === 'variables'}
onSelect={() => setSelectedType('variables')}
icon={<Zap size={20} />}
title="Variables Only Deployment"
description="Faster deployment that updates runtime variables and restarts pods. Does not rebuild images."
disabled={loading}
/>
</div>

{selectedType === 'variables' && (
<div
className="mt-6 p-4 rounded-lg flex gap-3"
style={{
backgroundColor: '#fffbeb',
borderWidth: '1px',
borderStyle: 'solid',
borderColor: '#fde68a',
color: '#78350f'
}}
>
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5" />
<div>
<h4 className="font-medium">Partial Deployment Warning</h4>
<p className="text-sm mt-1">
Some changes will not fully apply with a variables only deployment. Runtime variables will update now. Build scoped behaviour and other changes will only take effect after a full deployment.
</p>
</div>
<Button data-cy="deploy-button" disabled={loading} onClick={() => deployEnvironmentLatestMutation()}>
{loading && <Loader2 className="animate-spin" />} Deploy
</Button>
</>
</div>
)}

<div className="flex justify-end mt-6">
<Button data-cy="deploy-button" disabled={loading} onClick={() => deployEnvironmentLatestMutation()}>
{loading && <Loader2 className="animate-spin" />} Deploy
</Button>
</div>
</section>
);
};
Expand Down
11 changes: 9 additions & 2 deletions src/lib/mutation/deployEnvironmentLatest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { gql } from '@apollo/client';

export default gql`
mutation deployEnvironmentLatest($environmentId: Int!) {
deployEnvironmentLatest(input: { environment: { id: $environmentId } })
mutation deployEnvironmentLatest($environmentId: Int!, $envVarOnly: String = "false") {
deployEnvironmentLatest(input: { environment: { id: $environmentId },
buildVariables: [
{
name: "LAGOON_VARIABLES_ONLY",
value: $envVarOnly
}
]
})
}
`;