Skip to content

Commit

Permalink
feat(core/managed): visual re-treatment of statuses, constraints, and…
Browse files Browse the repository at this point in the history
… more (#8600)

* feat(core/managed): re-work status bubble color pallette slightly

* feat(core/managed): fix typo, status quantity, show count of pinned versions on environments

* feat(core/managed): add pinned visual treatment to version pills on overview

* feat(core/managed): tweak the padding on StatusBubble

* feat(core/presentation): add cloudWaiting icon

* feat(core/managed): add warning that a different version is pinned

* feat(core/managed): visually re-treat environment cards/bubbles

* feat(core/managed): further tweaking of colors, status treatment

* feat(core/managed): when there are multiple artifacts, show refs on pills
  • Loading branch information
Erik Munson committed Sep 28, 2020
1 parent a533cd9 commit c71e950
Show file tree
Hide file tree
Showing 18 changed files with 190 additions and 91 deletions.
4 changes: 2 additions & 2 deletions app/scripts/modules/core/src/domain/IManagedEntity.ts
Expand Up @@ -59,7 +59,7 @@ export interface IManagedResourceSummary {
};
}

export interface IManagedEnviromentSummary {
export interface IManagedEnvironmentSummary {
name: string;
resources: string[];
artifacts: Array<{
Expand Down Expand Up @@ -144,7 +144,7 @@ export interface IManagedArtifactSummary {

interface IManagedApplicationEntities {
resources: IManagedResourceSummary[];
environments: IManagedEnviromentSummary[];
environments: IManagedEnvironmentSummary[];
artifacts: IManagedArtifactSummary[];
}

Expand Down
67 changes: 51 additions & 16 deletions app/scripts/modules/core/src/managed/ArtifactDetail.tsx
@@ -1,10 +1,16 @@
import React, { memo, useMemo } from 'react';
import classNames from 'classnames';
import { useRouter } from '@uirouter/react';
import { useTransition, animated, UseTransitionProps } from 'react-spring';
import { DateTime } from 'luxon';

import { relativeTime, timestamp } from '../utils';
import { IManagedArtifactSummary, IManagedArtifactVersion, IManagedResourceSummary } from '../domain';
import {
IManagedArtifactSummary,
IManagedArtifactVersion,
IManagedEnvironmentSummary,
IManagedResourceSummary,
} from '../domain';
import { Application } from '../application';
import { useEventListener, Markdown } from '../presentation';

Expand Down Expand Up @@ -48,7 +54,7 @@ const cardTransitionConfig = {
// When react-spring v9 is released, this can be changed
// to a function that returns { to: inStyles, delay: 180 }
enter: () => async (next: (_: React.CSSProperties) => any) => {
await new Promise(resolve => setTimeout(resolve, 180));
await new Promise((resolve) => setTimeout(resolve, 180));
next(inStyles);
},
leave: outStyles,
Expand All @@ -61,6 +67,7 @@ type IEnvironmentCardsProps = Pick<
'application' | 'reference' | 'version' | 'allVersions' | 'resourcesByEnvironment'
> & {
environment: IManagedArtifactSummary['versions'][0]['environments'][0];
pinnedVersion: string;
};

const EnvironmentCards = memo(
Expand All @@ -80,14 +87,32 @@ const EnvironmentCards = memo(
reference,
version: versionDetails,
allVersions,
pinnedVersion,
resourcesByEnvironment,
}: IEnvironmentCardsProps) => {
const {
stateService: { go },
} = useRouter();

const pinnedAtMillis = pinned?.at ? DateTime.fromISO(pinned.at).toMillis() : null;

const differentVersionPinnedCard = pinnedVersion &&
pinnedVersion !== versionDetails.version &&
!['vetoed', 'skipped'].includes(state) && (
<StatusCard
iconName="cloudWaiting"
appearance="warning"
background={true}
title="A different version is pinned here"
actions={<Button onClick={() => go('.', { version: pinnedVersion })}>See version</Button>}
/>
);

const pinnedCard = pinned && (
<StatusCard
iconName="pin"
appearance="warning"
background={true}
title={
<span className="sp-group-margin-xs-xaxis">
Pinned here {relativeTime(pinnedAtMillis)}{' '}
Expand Down Expand Up @@ -129,7 +154,7 @@ const EnvironmentCards = memo(
() =>
[...(statelessConstraints || []), ...(statefulConstraints || [])]
.filter(({ type }) => isConstraintSupported(type))
.map(constraint => (
.map((constraint) => (
<ConstraintCard
key={constraint.type}
application={application}
Expand All @@ -143,22 +168,24 @@ const EnvironmentCards = memo(
);

const transitions = useTransition(
[...constraintCards, ...[versionStateCard, pinnedCard].filter(Boolean)],
[...constraintCards, ...[versionStateCard, pinnedCard, differentVersionPinnedCard].filter(Boolean)],
({ key }) => key,
cardTransitionConfig,
);

return (
<>
{/*
* Since transitions trail in ascending order, we need to reverse them
* to get the trail to go up the the list instead of down.
*/
transitions.reverse().map(({ item: card, key, props }) => (
<animated.div key={key} className="sp-margin-2xs-bottom" style={props}>
{card}
</animated.div>
))}
{
/*
* Since transitions trail in ascending order, we need to reverse them
* to get the trail to go up the the list instead of down.
*/
transitions.reverse().map(({ item: card, key, props }) => (
<animated.div key={key} style={props}>
{card}
</animated.div>
))
}
</>
);
},
Expand All @@ -176,6 +203,7 @@ export interface IArtifactDetailProps {
reference: string;
version: IManagedArtifactVersion;
allVersions: IManagedArtifactSummary['versions'];
allEnvironments: IManagedEnvironmentSummary[];
resourcesByEnvironment: { [environment: string]: IManagedResourceSummary[] };
onRequestClose: () => any;
}
Expand All @@ -186,6 +214,7 @@ export const ArtifactDetail = ({
reference,
version: versionDetails,
allVersions,
allEnvironments,
resourcesByEnvironment,
onRequestClose,
}: IArtifactDetailProps) => {
Expand Down Expand Up @@ -265,8 +294,13 @@ export const ArtifactDetail = ({
{git?.repo && <VersionMetadataItem label="Repository" value={`${git.project}/${git.repo.name}`} />}
</div>
</div>
{environments.map(environment => {
{environments.map((environment) => {
const { name: environmentName, state } = environment;

const { pinnedVersion } = allEnvironments
.find(({ name }) => name === environmentName)
.artifacts.find(({ reference: referenceToMatch }) => referenceToMatch === reference);

return (
<EnvironmentRow
key={environmentName}
Expand All @@ -280,13 +314,14 @@ export const ArtifactDetail = ({
reference={reference}
version={versionDetails}
allVersions={allVersions}
pinnedVersion={pinnedVersion}
resourcesByEnvironment={resourcesByEnvironment}
/>
</div>
<div className="sp-margin-l-top">
{resourcesByEnvironment[environmentName]
.filter(resource => shouldDisplayResource(reference, resource))
.map(resource => (
.filter((resource) => shouldDisplayResource(reference, resource))
.map((resource) => (
<div key={resource.id} className="flex-container-h middle">
{state === 'deploying' && (
<div
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/modules/core/src/managed/ArtifactRow.less
Expand Up @@ -12,7 +12,7 @@
}

&.selected {
background-color: #c7def5;
background-color: #dbe5eb;
}

.row-content {
Expand Down Expand Up @@ -123,7 +123,7 @@
&.selected {
.environment-stage.pending,
.environment-stage.skipped {
background-color: #c7def5;
background-color: #dbe5eb;
}
}

Expand Down
12 changes: 4 additions & 8 deletions app/scripts/modules/core/src/managed/ArtifactsList.tsx
Expand Up @@ -25,7 +25,7 @@ export function ArtifactsList({ artifacts, selectedVersion, versionSelected }: I
return (
<div>
{artifacts.map(({ versions, name, reference }) =>
versions.map(version => (
versions.map((version) => (
<ArtifactRow
key={`${name}-${version.version}`}
isSelected={
Expand Down Expand Up @@ -87,11 +87,7 @@ export const ArtifactRow = ({ isSelected, clickHandler, version: versionInfo, re
<div className="row-content flex-container-v left sp-padding-m-top sp-padding-l-bottom sp-padding-s-xaxis">
{(build?.number || build?.id) && (
<div className="flex-container-h sp-margin-s-bottom">
<Pill
bgColor={isSelected ? '#2c4b5f' : undefined}
textColor={isSelected ? '#c7def5' : undefined}
text={`#${build.number || build.id} ${name || ''}`}
/>
<Pill bgColor={isSelected ? '#2e4b5f' : undefined} text={`#${build.number || build.id} ${name || ''}`} />
</div>
)}
<div className="row-middle-section flex-container-h space-between">
Expand All @@ -108,7 +104,7 @@ export const ArtifactRow = ({ isSelected, clickHandler, version: versionInfo, re
</div>
<div className="sp-margin-s-left">
<StatusBubbleStack
borderColor={isSelected ? '#c7def5' : isHovered ? '#e8eaf2' : 'var(--color-alabaster)'}
borderColor={isSelected ? '#dbe5eb' : isHovered ? '#e8eaf2' : 'var(--color-alabaster)'}
maxBubbles={3}
statuses={getArtifactStatuses(versionInfo)}
/>
Expand Down Expand Up @@ -140,7 +136,7 @@ function getArtifactStatuses({ environments }: IManagedArtifactVersion): Artifac

const isConstraintPendingManualJudgement = (constraint: IStatefulConstraint) =>
constraint.type == 'manual-judgement' && constraint.status == StatefulConstraintStatus.PENDING;
const requiresManualApproval = environments.some(environment =>
const requiresManualApproval = environments.some((environment) =>
environment.statefulConstraints?.some(isConstraintPendingManualJudgement),
);
if (requiresManualApproval) {
Expand Down
15 changes: 11 additions & 4 deletions app/scripts/modules/core/src/managed/EnvironmentRow.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import classNames from 'classnames';

import { IManagedResourceSummary } from '../domain';
import { IManagedResourceSummary, IManagedEnvironmentSummary } from '../domain';
import { Icon } from '../presentation';

import { StatusBubble } from './StatusBubble';
Expand All @@ -14,11 +14,11 @@ import './EnvironmentRow.less';
interface IEnvironmentRowProps {
name: string;
resources?: IManagedResourceSummary[];
hasPinnedVersions?: boolean;
pinnedVersions?: IManagedEnvironmentSummary['artifacts'];
children?: React.ReactNode;
}

export function EnvironmentRow({ name, resources = [], hasPinnedVersions, children }: IEnvironmentRowProps) {
export function EnvironmentRow({ name, resources = [], pinnedVersions, children }: IEnvironmentRowProps) {
const [isCollapsed, setIsCollapsed] = useState(false);
const isCritical = useEnvironmentTypeFromResources(resources);

Expand All @@ -34,7 +34,14 @@ export function EnvironmentRow({ name, resources = [], hasPinnedVersions, childr
<EnvironmentBadge name={name} critical={isCritical} />
</div>
<div className="flex-container-h flex-grow flex-pull-right">
{hasPinnedVersions && <StatusBubble iconName="pin" appearance="warning" size="small" />}
{pinnedVersions?.length > 0 ? (
<StatusBubble
iconName="pin"
appearance="warning"
size="small"
quantity={pinnedVersions.length > 1 ? pinnedVersions.length : null}
/>
) : null}
</div>
<div className="expand" onClick={() => setIsCollapsed(!isCollapsed)}>
{isCollapsed && <Icon name="accordionExpand" size="extraSmall" />}
Expand Down
7 changes: 4 additions & 3 deletions app/scripts/modules/core/src/managed/Environments.tsx
Expand Up @@ -82,7 +82,7 @@ export function Environments({ app }: IEnvironmentsProps) {
const resourcesByEnvironment = useMemo(
() =>
environments.reduce((byEnvironment, { name, resources: resourceIds }) => {
byEnvironment[name] = resourceIds.map(id => resourcesById[id]);
byEnvironment[name] = resourceIds.map((id) => resourcesById[id]);
return byEnvironment;
}, {} as { [environment: string]: IManagedResourceSummary[] }),
[environments, resourcesById],
Expand Down Expand Up @@ -145,7 +145,7 @@ export function Environments({ app }: IEnvironmentsProps) {
<ArtifactsList
artifacts={artifacts}
selectedVersion={selectedVersion}
versionSelected={clickedVersion => {
versionSelected={(clickedVersion) => {
if (!isEqual(clickedVersion, selectedVersion)) {
go(selectedVersion ? '.' : '.artifactVersion', clickedVersion);
}
Expand All @@ -161,7 +161,7 @@ export function Environments({ app }: IEnvironmentsProps) {
<EnvironmentsHeader
app={app}
resourceInfo={{
managed: resources.filter(r => !r.isPaused).length,
managed: resources.filter((r) => !r.isPaused).length,
total: resources.length,
}}
/>
Expand All @@ -179,6 +179,7 @@ export function Environments({ app }: IEnvironmentsProps) {
reference={item.selectedArtifactDetails.reference}
version={item.selectedVersionDetails}
allVersions={item.selectedArtifactDetails.versions}
allEnvironments={environments}
resourcesByEnvironment={resourcesByEnvironment}
onRequestClose={() => go('^')}
/>
Expand Down
16 changes: 9 additions & 7 deletions app/scripts/modules/core/src/managed/EnvironmentsList.tsx
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { pickBy, values } from 'lodash';

import { Application } from 'core/application';
import { IManagedEnviromentSummary, IManagedResourceSummary, IManagedArtifactSummary } from '../domain';
import { IManagedEnvironmentSummary, IManagedResourceSummary, IManagedArtifactSummary } from '../domain';

import { ManagedResourceObject } from './ManagedResourceObject';
import { EnvironmentRow } from './EnvironmentRow';
Expand All @@ -15,7 +15,7 @@ function shouldDisplayResource(resource: IManagedResourceSummary) {

interface IEnvironmentsListProps {
application: Application;
environments: IManagedEnviromentSummary[];
environments: IManagedEnvironmentSummary[];
resourcesById: { [id: string]: IManagedResourceSummary };
artifacts: IManagedArtifactSummary[];
}
Expand All @@ -29,19 +29,19 @@ export function EnvironmentsList({
return (
<div>
{environments.map(({ name, resources, artifacts }) => {
const hasPinnedVersions = artifacts.some(({ pinnedVersion }) => pinnedVersion);
const pinnedVersions = artifacts.filter(({ pinnedVersion }) => pinnedVersion);

return (
<EnvironmentRow
key={name}
name={name}
hasPinnedVersions={hasPinnedVersions}
resources={values(pickBy(resourcesById, resource => resources.indexOf(resource.id) > -1))}
pinnedVersions={pinnedVersions}
resources={values(pickBy(resourcesById, (resource) => resources.indexOf(resource.id) > -1))}
>
{resources
.map(resourceId => resourcesById[resourceId])
.map((resourceId) => resourcesById[resourceId])
.filter(shouldDisplayResource)
.map(resource => {
.map((resource) => {
const artifactVersionsByState =
resource.artifact &&
artifacts.find(({ reference }) => reference === resource.artifact.reference)?.versions;
Expand All @@ -52,6 +52,8 @@ export function EnvironmentsList({
application={application}
key={resource.id}
resource={resource}
environment={name}
showReferenceName={allArtifacts.length > 1}
artifactVersionsByState={artifactVersionsByState}
artifactDetails={artifactDetails}
/>
Expand Down

0 comments on commit c71e950

Please sign in to comment.