Skip to content

Commit

Permalink
fix(ui): stage phase icon (#3164)
Browse files Browse the repository at this point in the history
Signed-off-by: Mayursinh Sarvaiya <[email protected]>
  • Loading branch information
Marvin9 authored Jan 2, 2025
1 parent 0dc9dc5 commit 0a12294
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 9 deletions.
59 changes: 59 additions & 0 deletions ui/src/features/common/stage-phase/stage-phase-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
faCircle,
faCircleMinus,
faMagnifyingGlass,
faTimesCircle,
IconDefinition
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from 'antd';
import classNames from 'classnames';

import styles from './styles.module.less';
import { TruckIcon } from './truck-icon/truck-icon';
import { StagePhase } from './utils';

export const StagePhaseIcon = (props: { phase: StagePhase; className?: string }) => {
let icon: IconDefinition = faCircleMinus;

switch (props.phase) {
case StagePhase.Steady:
icon = faCircle;
break;

case StagePhase.Verifying:
icon = faMagnifyingGlass;
break;

case StagePhase.Failed:
icon = faTimesCircle;
break;
}

return (
<Tooltip
title={
<>
<b>Stage phase:</b> {props.phase}
</>
}
>
{props.phase === StagePhase.Promoting ? (
<>
<TruckIcon />
</>
) : (
<FontAwesomeIcon
icon={icon}
className={classNames(props.className, {
'text-gray-400': props.phase === StagePhase.NotApplicable,
'text-red-400': props.phase === StagePhase.Failed,
'text-green-400': props.phase === StagePhase.Steady,
'text-blue-500': props.phase === StagePhase.Verifying,
[styles.magnifyingGlass]: props.phase === StagePhase.Verifying
})}
/>
)}
</Tooltip>
);
};
21 changes: 21 additions & 0 deletions ui/src/features/common/stage-phase/styles.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.magnifyingGlass {
animation: circle-animation 1s linear infinite;
}

@keyframes circle-animation {
0% {
transform: translate(0, -1px);
}
25% {
transform: translate(1px, 0);
}
50% {
transform: translate(0, 1px);
}
75% {
transform: translate(-1px, 0);
}
100% {
transform: translate(0, -1px);
}
}
73 changes: 73 additions & 0 deletions ui/src/features/common/stage-phase/truck-icon/styles.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.truckContainer {
position: relative;
display: inline-block;
@apply text-xl;
}

.truckIcon {
position: relative;
z-index: 1;
animation: bounce 0.6s ease-in-out infinite;
@apply text-blue-500;
}

@keyframes bounce {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-1px);
}
}

.exhaustParticle {
position: absolute;
bottom: 10px;
left: -5px;
width: 2px;
height: 2px;
background-color: rgba(150, 150, 150, 0.7);
border-radius: 50%;
opacity: 0;
animation: puff 1.5s ease-out infinite;
}

@keyframes puff {
0% {
opacity: 1;
transform: translate(0, 0) scale(1);
width: 4px;
}
50% {
opacity: 1;
transform: translate(calc(var(--directionX)), calc(-15px + var(--directionY)))
scale(calc(1.2 + var(--scale)));
width: calc(4px + 2px * var(--scale));
}
100% {
opacity: 0;
transform: translate(calc(var(--directionX)), calc(-30px + var(--directionY)))
scale(calc(1.2 + var(--scale)));
width: calc(4px + 2px * var(--scale));
}
}

.exhaustParticle:nth-child(1) {
--directionX: -5px;
--directionY: 0px;
--scale: 0.5;
animation-delay: 0s;
}
.exhaustParticle:nth-child(2) {
--directionX: -10px;
--directionY: 5px;
--scale: 0.4;
animation-delay: 0.2s;
}
.exhaustParticle:nth-child(3) {
--directionX: -8px;
--directionY: 10px;
--scale: 0.6;
animation-delay: 0.4s;
}
13 changes: 13 additions & 0 deletions ui/src/features/common/stage-phase/truck-icon/truck-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { faTruckArrowRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

import styles from './styles.module.less';

export const TruckIcon = () => (
<div className={styles.truckContainer}>
<FontAwesomeIcon icon={faTruckArrowRight} className={styles.truckIcon} />
<div className={styles.exhaustParticle}></div>
<div className={styles.exhaustParticle}></div>
<div className={styles.exhaustParticle}></div>
</div>
);
8 changes: 8 additions & 0 deletions ui/src/features/common/stage-phase/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// in par with stage_types.go
export enum StagePhase {
NotApplicable = 'NotApplicable',
Steady = 'Steady',
Promoting = 'Promoting',
Verifying = 'Verifying',
Failed = 'Failed'
}
19 changes: 10 additions & 9 deletions ui/src/features/stage/stage-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import { useMemo, useState } from 'react';
import { generatePath, useNavigate, useParams } from 'react-router-dom';

import { paths } from '@ui/config/paths';
import { Description } from '@ui/features/common/description';
import { HealthStatusIcon } from '@ui/features/common/health-status/health-status-icon';
import { ManifestPreview } from '@ui/features/common/manifest-preview';
import { StagePhaseIcon } from '@ui/features/common/stage-phase/stage-phase-icon';
import { StagePhase } from '@ui/features/common/stage-phase/utils';
import { useImages } from '@ui/features/project/pipelines/utils/useImages';
import { getConfig } from '@ui/gen/service/v1alpha1/service-KargoService_connectquery';
import { Stage, StageSchema, VerificationInfo } from '@ui/gen/v1alpha1/generated_pb';
import { timestampDate } from '@ui/utils/connectrpc-utils';

import { Description } from '../common/description';
import { ManifestPreview } from '../common/manifest-preview';
import { useImages } from '../project/pipelines/utils/useImages';

import { FreightHistory } from './freight-history';
import { Promotions } from './promotions';
import { RequestedFreight } from './requested-freight';
Expand Down Expand Up @@ -56,11 +57,11 @@ export const StageDetails = ({ stage }: { stage: Stage }) => {
{stage && (
<div className='flex flex-col h-full'>
<div className='flex items-center justify-between'>
<div className='flex gap-1 items-start'>
<HealthStatusIcon
health={stage.status?.health}
style={{ marginRight: '10px', marginTop: '10px' }}
/>
<div className='flex gap-1 items-center'>
<StagePhaseIcon className='mr-2' phase={stage.status?.phase as StagePhase} />
{!!stage.status?.health && (
<HealthStatusIcon health={stage.status?.health} style={{ marginRight: '10px' }} />
)}
<div>
<Typography.Title level={1} style={{ margin: 0 }}>
{stage.metadata?.name}
Expand Down

0 comments on commit 0a12294

Please sign in to comment.