Skip to content

Commit

Permalink
fix: better default color picking + don't change colors on new stages (
Browse files Browse the repository at this point in the history
…akuity#930)

Signed-off-by: Remington Breeze <remington@breeze.software>
  • Loading branch information
rbreeze authored Oct 10, 2023
1 parent 66a1848 commit 4aa19bf
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 144 deletions.
5 changes: 5 additions & 0 deletions ui/src/context/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createContext } from 'react';

import { ColorMap } from '@ui/features/stage/utils';

export const ColorContext = createContext({} as ColorMap);
11 changes: 5 additions & 6 deletions ui/src/features/freightline/freightline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useMutation } from '@tanstack/react-query';
import { Tooltip, message } from 'antd';
import { formatDistance } from 'date-fns';
import React, { useEffect, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';

import { ColorContext } from '@ui/context/colors';
import {
promoteStage,
promoteSubscribers
Expand All @@ -21,7 +22,6 @@ import { StageIndicators } from './stage-indicators';
export const Freightline = (props: {
freight: Freight[];
stagesPerFreight: { [key: string]: Stage[] };
stageColorMap: { [key: string]: string };
promotingStage?: Stage;
setPromotingStage: (stage?: Stage) => void;
promotionType?: PromotionType;
Expand All @@ -31,7 +31,6 @@ export const Freightline = (props: {
const {
freight,
stagesPerFreight,
stageColorMap,
promotingStage,
setPromotingStage,
promotionType,
Expand All @@ -44,6 +43,8 @@ export const Freightline = (props: {

const getSeconds = (ts?: Timestamp): number => Number(ts?.seconds) || 0;

const stageColorMap = useContext(ColorContext);

const { mutate: promoteSubscribersAction } = useMutation({
...promoteSubscribers.useMutation(),
onError: (err) => {
Expand Down Expand Up @@ -135,7 +136,6 @@ export const Freightline = (props: {
freight={f || undefined}
key={id}
stages={stagesPerFreight[id] || []}
stageColorMap={stageColorMap}
promotable={promotionEligible[id]}
promoting={promotingStage}
promotionType={promotionType || 'default'}
Expand Down Expand Up @@ -254,7 +254,6 @@ const FreightContents = (props: {
const FreightItem = (props: {
freight?: Freight;
stages: Stage[];
stageColorMap: { [key: string]: string };
promotable?: boolean;
promoting?: Stage;
promotionType?: PromotionType;
Expand Down Expand Up @@ -301,7 +300,7 @@ const FreightItem = (props: {
}}
>
<div className='flex w-full h-full mb-1 items-center justify-center'>
<StageIndicators stages={stages} stageColorMap={props.stageColorMap} />
<StageIndicators stages={stages} />
<FreightContents
highlighted={
((stages || []).length > 0 && !promoting) || (promoting && promotable) || false
Expand Down
13 changes: 7 additions & 6 deletions ui/src/features/freightline/stage-indicators.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Tooltip } from 'antd';
import { useContext } from 'react';

import { ColorContext } from '@ui/context/colors';
import { Stage } from '@ui/gen/v1alpha1/types_pb';

const StageIndicator = (props: { stage: Stage; backgroundColor: string }) => {
Expand All @@ -16,23 +18,22 @@ const StageIndicator = (props: { stage: Stage; backgroundColor: string }) => {
);
};

export const StageIndicators = (props: {
stages: Stage[];
stageColorMap: { [key: string]: string };
}) =>
(props.stages || []).length > 0 ? (
export const StageIndicators = (props: { stages: Stage[] }) => {
const stageColorMap = useContext(ColorContext);
return (props.stages || []).length > 0 ? (
<div
className={`flex flex-col align-center h-full justify-center w-full flex-grow mr-2`}
style={{ width: '80px' }}
>
{(props.stages || []).map((s) => (
<StageIndicator
stage={s}
backgroundColor={props.stageColorMap[s?.metadata?.uid || '']}
backgroundColor={stageColorMap[s?.metadata?.uid || '']}
key={s?.metadata?.uid}
/>
))}
</div>
) : (
<></>
);
};
6 changes: 3 additions & 3 deletions ui/src/features/project/project-details/images.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Switch, Tooltip } from 'antd';
import classNames from 'classnames';
import { useMemo, useState } from 'react';
import { useContext, useMemo, useState } from 'react';
import { generatePath, useNavigate } from 'react-router-dom';

import { paths } from '@ui/config/paths';
import { getStageColors } from '@ui/features/stage/utils';
import { ColorContext } from '@ui/context/colors';
import { Stage } from '@ui/gen/v1alpha1/types_pb';
import { useLocalStorage } from '@ui/utils/use-local-storage';

Expand Down Expand Up @@ -77,9 +77,9 @@ const ImageTagRow = ({
};

export const Images = ({ projectName, stages }: { projectName: string; stages: Stage[] }) => {
const colors = useContext(ColorContext);
const images = useMemo(() => {
const images = new Map<string, Map<string, StageStyleMap>>();
const colors = getStageColors([...stages]);
stages.forEach((stage) => {
const len = stage.status?.history?.length || 0;
stage.status?.history?.forEach((freight, i) => {
Expand Down
209 changes: 106 additions & 103 deletions ui/src/features/project/project-details/project-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React from 'react';
import { useParams } from 'react-router-dom';

import { transport } from '@ui/config/transport';
import { ColorContext } from '@ui/context/colors';
import { LoadingState } from '@ui/features/common';
import { Freightline, PromotionType } from '@ui/features/freightline/freightline';
import { StageDetails } from '@ui/features/stage/stage-details';
Expand Down Expand Up @@ -89,7 +90,7 @@ export const ProjectDetails = () => {
return () => cancel.abort();
}, [isLoading, isVisible, name]);

const [nodes, connectors, box] = React.useMemo(() => {
const [nodes, connectors, box, sortedStages] = React.useMemo(() => {
if (!data) {
return [[], []];
}
Expand All @@ -98,8 +99,6 @@ export const ProjectDetails = () => {
g.setGraph({ rankdir: 'LR' });
g.setDefaultEdgeLabel(() => ({}));

const colors = getStageColors(data.stages);

const myNodes = data.stages
.slice()
.sort((a, b) => a.metadata?.name?.localeCompare(b.metadata?.name || '') || 0)
Expand All @@ -108,7 +107,7 @@ export const ProjectDetails = () => {
{
data: stage,
type: NodeType.STAGE,
color: colors[stage?.metadata?.uid || '']
color: '#000'
},
...(stage.spec?.subscriptions?.repos?.images || []).map((image) => ({
data: image,
Expand Down Expand Up @@ -212,18 +211,23 @@ export const ProjectDetails = () => {
height: 0
}
);
return [nodes, connectors, box];
}, [data]);

const sortedStages = React.useMemo(() => {
return nodes
const sortedStages = nodes
.filter((item) => item.type === NodeType.STAGE)
.sort((a, b) => a.left - b.left)
.map((item) => item.data) as Stage[];
}, [nodes]);

const stageColorMap = getStageColors(name || '', sortedStages);
nodes.forEach((node) => {
if (node.type === NodeType.STAGE) {
node.color = stageColorMap[node.data?.metadata?.uid || ''];
}
});

return [nodes, connectors, box, sortedStages];
}, [data]);

const [stagesPerFreight, setStagesPerFreight] = React.useState<{ [key: string]: Stage[] }>({});
const [stageColorMap, setStageColorMap] = React.useState<{ [key: string]: string }>({});
const [promotingStage, setPromotingStage] = React.useState<Stage | undefined>();
const [promotionType, setPromotionType] = React.useState('default' as PromotionType);
const [confirmingPromotion, setConfirmingPromotion] = React.useState<string | undefined>();
Expand All @@ -233,8 +237,6 @@ export const ProjectDetails = () => {

React.useEffect(() => {
const stagesPerFreight: { [key: string]: Stage[] } = {};

setStageColorMap(getStageColors(data?.stages || []));
(data?.stages || []).forEach((stage) => {
const items = stagesPerFreight[stage.status?.currentFreight?.id || ''] || [];
stagesPerFreight[stage.status?.currentFreight?.id || ''] = [...items, stage];
Expand Down Expand Up @@ -269,104 +271,105 @@ export const ProjectDetails = () => {

return (
<div className='flex flex-col flex-grow'>
<Freightline
freight={freightData?.groups['']?.freight || []}
stagesPerFreight={stagesPerFreight}
stageColorMap={stageColorMap}
promotingStage={promotingStage}
setPromotingStage={setPromotingStage}
promotionType={promotionType}
confirmingPromotion={confirmingPromotion}
setConfirmingPromotion={setConfirmingPromotion}
/>
<div className='flex flex-grow w-full'>
<div className={`overflow-hidden flex-grow w-full ${styles.dag}`}>
<div className='text-sm mb-4 font-semibold p-6'>
<FontAwesomeIcon icon={faDiagramProject} className='mr-2' />
PIPELINE
</div>
<div className='overflow-auto p-6'>
<div
className='relative'
style={{ width: box?.width, height: box?.height, margin: '0 auto' }}
>
{nodes?.map((node, index) => (
<div
key={index}
className='absolute'
style={{
left: node.left,
top: node.top,
width: node.width,
height: node.height
}}
>
{node.type === NodeType.STAGE ? (
<StageNode
stage={node.data}
color={node.color}
height={node.height}
projectName={name}
faded={isFaded(node.data)}
hasNoSubscribers={
(subscribersByStage[node?.data?.metadata?.name || ''] || []).length === 0
}
onPromoteClick={(type: PromotionType) => {
if (promotingStage?.metadata?.name === node.data?.metadata?.name) {
setPromotingStage(undefined);
} else {
setPromotingStage(node.data);
setPromotionType(type);
}
setConfirmingPromotion(undefined);
}}
promoting={
promotingStage?.metadata?.name === node.data?.metadata?.name
? promotionType
: undefined
}
/>
) : (
<RepoNode nodeData={node} height={node.height} />
)}
</div>
))}
{connectors?.map((connector) =>
connector.map((line, i) => (
<ColorContext.Provider value={getStageColors(name || '', sortedStages || [])}>
<Freightline
freight={freightData?.groups['']?.freight || []}
stagesPerFreight={stagesPerFreight}
promotingStage={promotingStage}
setPromotingStage={setPromotingStage}
promotionType={promotionType}
confirmingPromotion={confirmingPromotion}
setConfirmingPromotion={setConfirmingPromotion}
/>
<div className='flex flex-grow w-full'>
<div className={`overflow-hidden flex-grow w-full ${styles.dag}`}>
<div className='text-sm mb-4 font-semibold p-6'>
<FontAwesomeIcon icon={faDiagramProject} className='mr-2' />
PIPELINE
</div>
<div className='overflow-auto p-6'>
<div
className='relative'
style={{ width: box?.width, height: box?.height, margin: '0 auto' }}
>
{nodes?.map((node, index) => (
<div
className='absolute bg-gray-400'
key={index}
className='absolute'
style={{
padding: 0,
margin: 0,
height: lineThickness,
width: line.width,
left: line.x,
top: line.y,
transform: `rotate(${line.angle}deg)`
left: node.left,
top: node.top,
width: node.width,
height: node.height
}}
key={i}
/>
))
)}
>
{node.type === NodeType.STAGE ? (
<StageNode
stage={node.data}
color={node.color}
height={node.height}
projectName={name}
faded={isFaded(node.data)}
hasNoSubscribers={
(subscribersByStage[node?.data?.metadata?.name || ''] || []).length === 0
}
onPromoteClick={(type: PromotionType) => {
if (promotingStage?.metadata?.name === node.data?.metadata?.name) {
setPromotingStage(undefined);
} else {
setPromotingStage(node.data);
setPromotionType(type);
}
setConfirmingPromotion(undefined);
}}
promoting={
promotingStage?.metadata?.name === node.data?.metadata?.name
? promotionType
: undefined
}
/>
) : (
<RepoNode nodeData={node} height={node.height} />
)}
</div>
))}
{connectors?.map((connector) =>
connector.map((line, i) => (
<div
className='absolute bg-gray-400'
style={{
padding: 0,
margin: 0,
height: lineThickness,
width: line.width,
left: line.x,
top: line.y,
transform: `rotate(${line.angle}deg)`
}}
key={i}
/>
))
)}
</div>
</div>
</div>
</div>
<div
className='text-gray-300 text-sm'
style={{
width: '400px',
backgroundColor: '#222'
}}
>
<h3 className='bg-black px-6 pb-3 pt-4 flex items-center'>
<FontAwesomeIcon icon={faDocker} className='mr-2' /> IMAGES
</h3>
<div className='p-4'>
<Images projectName={name as string} stages={sortedStages} />
<div
className='text-gray-300 text-sm'
style={{
width: '400px',
backgroundColor: '#222'
}}
>
<h3 className='bg-black px-6 pb-3 pt-4 flex items-center'>
<FontAwesomeIcon icon={faDocker} className='mr-2' /> IMAGES
</h3>
<div className='p-4'>
<Images projectName={name as string} stages={sortedStages || []} />
</div>
</div>
</div>
</div>
{stage && <StageDetails stage={stage} />}
{stage && <StageDetails stage={stage} />}
</ColorContext.Provider>
</div>
);
};
Loading

0 comments on commit 4aa19bf

Please sign in to comment.