Skip to content

Commit

Permalink
#1236 Horizontal display for promotions
Browse files Browse the repository at this point in the history
  • Loading branch information
dcoraboeuf committed Dec 16, 2024
1 parent 7d547e8 commit c6a1ae9
Show file tree
Hide file tree
Showing 25 changed files with 298 additions and 243 deletions.
7 changes: 3 additions & 4 deletions ontrack-web-core/components/branches/BranchBuilds.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import BuildBox from "@components/builds/BuildBox";
import {Button, Col, Popover, Row, Space, Spin, Table, Typography} from "antd";
import {FaCheckSquare, FaEyeSlash, FaSearch, FaSquare} from "react-icons/fa";
import PromotionRun from "@components/promotionRuns/PromotionRun";
import RangeSelector from "@components/common/RangeSelector";
import {useRouter} from "next/router";
import BuildFilterDropdown from "@components/branches/filters/builds/BuildFilterDropdown";
Expand All @@ -15,6 +14,7 @@ import {useConnection, useGraphQLClient} from "@components/providers/ConnectionC
import {gql} from "graphql-request";
import {buildUri, scmChangeLogUri} from "@components/common/Links";
import EntityNotificationsBadge from "@components/extension/notifications/EntityNotificationsBadge";
import PromotionRunStep from "@components/promotionRuns/PromotionRunStep";

const {Column} = Table;

Expand Down Expand Up @@ -233,10 +233,9 @@ export default function BranchBuilds({
<Space size={8}>
{
build.promotionRuns.map(promotionRun =>
<PromotionRun
<PromotionRunStep
key={promotionRun.id}
promotionRun={promotionRun}
size={24}
run={promotionRun}
/>
)
}
Expand Down
12 changes: 6 additions & 6 deletions ontrack-web-core/components/builds/BuildContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import BuildPromotionInfo from "@components/builds/BuildPromotionInfo";
export default function BuildContent({build}) {

const defaultLayout = [
{i: "promotions", x: 0, y: 0, w: 4, h: 18},
{i: "validations", x: 6, y: 0, w: 8, h: 9},
{i: "using", x: 4, y: 9, w: 4, h: 9},
{i: "usedBy", x: 8, y: 9, w: 4, h: 9},
{i: "notifications", x: 0, y: 18, w: 12, h: 9},
{i: "promotions", x: 0, y: 0, w: 12, h: 4},
{i: "validations", x: 0, y: 4, w: 12, h: 9},
{i: "using", x: 0, y: 13, w: 6, h: 9},
{i: "usedBy", x: 6, y: 13, w: 6, h: 9},
{i: "notifications", x: 0, y: 22, w: 12, h: 9},
]

const items = [
Expand Down Expand Up @@ -51,7 +51,7 @@ export default function BuildContent({build}) {
return (
<>
<StoredGridLayout
id="page-build-layout-v2"
id="page-build-layout-v3"
defaultLayout={defaultLayout}
items={items}
rowHeight={30}
Expand Down
10 changes: 6 additions & 4 deletions ontrack-web-core/components/builds/BuildPromotionInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react";
import {useGraphQLClient} from "@components/providers/ConnectionContextProvider";
import GridCell from "@components/grid/GridCell";
import {gql} from "graphql-request";
import {Timeline} from "antd";
import {Steps} from "antd";
import buildPromotionInfoItem from "@components/builds/BuildPromotionInfoItem";
import {useReloadState} from "@components/common/StateUtils";
import {gqlSlotPipelineData} from "@components/extension/environments/EnvironmentGraphQL";
Expand Down Expand Up @@ -34,6 +34,7 @@ export default function BuildPromotionInfo({build}) {
id
name
image
description
}
... on PromotionRun {
id
Expand Down Expand Up @@ -89,6 +90,7 @@ export default function BuildPromotionInfo({build}) {
})
)
})
itemList.reverse()
setItems(itemList)
}).finally(() => {
setLoading(false)
Expand All @@ -99,10 +101,10 @@ export default function BuildPromotionInfo({build}) {
return (
<>
<GridCell id="promotions" title="Promotions" padding={true}>
<Timeline
loading={loading}
mode="left"
<Steps
items={items}
labelPlacement="vertical"
size="small"
/>
</GridCell>
</>
Expand Down
14 changes: 5 additions & 9 deletions ontrack-web-core/components/builds/BuildPromotionInfoItem.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import {Dynamic} from "@components/common/Dynamic";

/**
* Used in a Steps component.
*/
export default function buildPromotionInfoItem({item, build, promotionLevel, onChange}) {
return ({
label: <Dynamic
path={`framework/build-promotion-info-item/${item.__typename}/Name`}
props={{item, build, promotionLevel, onChange}}
/>,
dot: <Dynamic
icon: <Dynamic
path={`framework/build-promotion-info-item/${item.__typename}/Dot`}
props={{item, build, promotionLevel, onChange}}
/>,
children: <Dynamic
path={`framework/build-promotion-info-item/${item.__typename}/Actions`}
props={{item, build, promotionLevel, onChange}}
/>,
status: 'finish',
})
}
4 changes: 4 additions & 0 deletions ontrack-web-core/components/common/ClassUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const actionClassName = (onClick, disabled, base = "") => {
const addons = onClick ? (disabled ? "ot-action ot-disabled" : "ot-action") : (disabled ? "ot-disabled" : "")
return `${base} ${addons}`
}
5 changes: 3 additions & 2 deletions ontrack-web-core/components/common/ProxyImage.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {useRestClient} from "@components/providers/ConnectionContextProvider";
import {useEffect, useState} from "react";
import {Tooltip} from "antd";
import {actionClassName} from "@components/common/ClassUtils";

/**
* This renders an image using a call to the REST API.
*/
export default function ProxyImage({restUri, alt, width, height, onClick, tooltipText}) {
export default function ProxyImage({restUri, alt, width, height, onClick, tooltipText, disabled = false}) {

const client = useRestClient()

Expand Down Expand Up @@ -38,7 +39,7 @@ export default function ProxyImage({restUri, alt, width, height, onClick, toolti
width={width}
height={height}
onClick={onClick}
className={onClick ? "ot-action" : undefined}
className={actionClassName(onClick, disabled)}
/>
</Tooltip>
}
Expand Down
29 changes: 19 additions & 10 deletions ontrack-web-core/components/common/icons/GeneratedIcon.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
import {getTextColorForBackground, numberToColorHsl} from "@components/common/colors/Colors";
import {Tooltip} from "antd";
import {actionClassName} from "@components/common/ClassUtils";

export default function GeneratedIcon({name, colorIndex, onClick, tooltipText}) {
export default function GeneratedIcon({name, colorIndex, onClick, tooltipText, size = 24, disabled = false}) {

const initials = generateInitials(name)
const initials = name && generateInitials(name)
const bgColor = numberToColorHsl(colorIndex)
const textColor = getTextColorForBackground(bgColor)

const fontSize = size * 0.5

return (
<>
<Tooltip title={tooltipText}>
{
name &&
<Tooltip title={tooltipText}>
<span
style={{
display: 'inline-block',
width: '2.1em',
height: '2.1em',
lineHeight: '2.1em',
width: `${size}px`,
maxWidth: `${size}px`,
height: `${size}px`,
maxHeight: `${size}px`,
lineHeight: `${size}px`,
textAlign: 'center',
backgroundColor: bgColor,
color: textColor,
// Adjust font-size slightly smaller so both letters fit nicely.
fontSize: '0.75em',
fontSize: `${fontSize}px`,
// Optionally a small border radius to smooth corners, but it's optional.
borderRadius: '0.1em',
verticalAlign: 'middle'
verticalAlign: 'middle',
filter: disabled ? 'grayscale(100%)' : undefined,
}}
onClick={onClick}
className={onClick ? 'ot-action' : undefined}
className={actionClassName(onClick, disabled)}
>
{initials}
</span>
</Tooltip>
</Tooltip>
}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {useGraphQLClient} from "@components/providers/ConnectionContextProvider"
import {gql} from "graphql-request";
import LoadingInline from "@components/common/LoadingInline";

export default function EnvironmentIcon({environmentId, onClick, tooltipText, size = 16}) {
export default function EnvironmentIcon({environmentId, onClick, showTooltip = true, tooltipText, size = 16}) {

const client = useGraphQLClient()
const [refreshState, refresh] = useReloadState()
Expand All @@ -35,7 +35,9 @@ export default function EnvironmentIcon({environmentId, onClick, tooltipText, si
).then(data => {
const env = data.environmentById;
setEnvironment(env)
setTooltip(tooltipText ?? env.name)
if (showTooltip) {
setTooltip(tooltipText ?? env.name)
}
}).finally(() => {
setLoading(false)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import {useEffect, useState} from "react";
import LoadingInline from "@components/common/LoadingInline";
import {gql} from "graphql-request";
import NotificationStatusBadge from "@components/extension/notifications/NotificationStatusBadge";
import {Space} from "antd";
import {Badge, Space} from "antd";

export default function EntityNotificationsBadge({entityType, entityId, href}) {
export default function EntityNotificationsBadge({entityType, entityId, href, showText = false, children}) {

const client = useGraphQLClient()
const [loading, setLoading] = useState(true)
const [statuses, setStatuses] = useState({})

const [badgeCount, setBadgeCount] = useState(0)
const [badgeColour, setBadgeColour] = useState('')

useEffect(() => {
if (client) {
setLoading(true)
Expand Down Expand Up @@ -54,6 +57,16 @@ export default function EntityNotificationsBadge({entityType, entityId, href}) {
}
})
setStatuses({success, running, error})
if (error) {
setBadgeCount(error)
setBadgeColour("red")
} else if (running) {
setBadgeCount(running)
setBadgeColour("blue")
} else if (success) {
setBadgeCount(success)
setBadgeColour("green")
}
}).finally(() => {
setLoading(false)
})
Expand All @@ -62,32 +75,45 @@ export default function EntityNotificationsBadge({entityType, entityId, href}) {

return (
<>
<LoadingInline
loading={loading}
text=""
>
<Space size={1}>
<NotificationStatusBadge
status="success"
count={statuses.success}
title={`${statuses.success} notification(s) have succeeded.`}
href={href}
/>
<NotificationStatusBadge
status="processing"
spin={true}
count={statuses.running}
title={`${statuses.running} notification(s) are still running.`}
href={href}
/>
<NotificationStatusBadge
status="error"
count={statuses.error}
title={`${statuses.error} notification(s) have failed.`}
href={href}
/>
</Space>
</LoadingInline>
{
children && <>
<Badge overflowCount={10} showZero={false} count={badgeCount} title="" color={badgeColour} size="small">
{children}
</Badge>
</>
}
{
!children &&
<LoadingInline
loading={loading}
text=""
>
<Space size={1}>
<NotificationStatusBadge
status="success"
count={statuses.success}
title={`${statuses.success} notification(s) have succeeded.`}
href={href}
showText={showText}
/>
<NotificationStatusBadge
status="processing"
spin={true}
count={statuses.running}
title={`${statuses.running} notification(s) are still running.`}
href={href}
showText={showText}
/>
<NotificationStatusBadge
status="error"
count={statuses.error}
title={`${statuses.error} notification(s) have failed.`}
href={href}
showText={showText}
/>
</Space>
</LoadingInline>
}
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,30 @@ import {Space, Tag, Typography} from "antd";
import Link from "next/link";
import {FaSpinner} from "react-icons/fa";

export default function NotificationStatusBadge({status, spin, count, href, title}) {
export default function NotificationStatusBadge({status, spin, count, href, title, showText = false}) {
return (
<>
{
count > 0 &&
<Tag
color={status}
title={title}
>
<Link href={href}>
<Space>
{
spin && <FaSpinner className="anticon-spin"/>
}
<Typography.Text color={status}>{count}</Typography.Text>
</Space>
</Link>
</Tag>
<Space>
<Tag
color={status}
title={showText ? undefined : title}
>
<Link href={href}>
<Space>
{
spin && <FaSpinner className="anticon-spin"/>
}
<Typography.Text color={status}>{count}</Typography.Text>
</Space>
</Link>
</Tag>
{
showText &&
<Typography.Text>{title}</Typography.Text>
}
</Space>
}
</>
)
Expand Down

This file was deleted.

Loading

0 comments on commit c6a1ae9

Please sign in to comment.