Merge pull request #7732 from tragiclifestories/gauge-color
Allow overriding colour in Gauge components
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Add new way to override color selection to progress bar/gauge components.
|
||||
|
||||
`Gauge`, `LinearGauge` and `GaugeCard` all accept a `getColor` prop,
|
||||
which is a function of the type:
|
||||
|
||||
```ts
|
||||
export type GaugePropsGetColor = (args: {
|
||||
palette: Palette;
|
||||
value: number;
|
||||
inverse?: boolean;
|
||||
max?: number;
|
||||
}) => string;
|
||||
```
|
||||
|
||||
Return a standard CSS color string (e.g. "red", "#f02020"), and the gauge will
|
||||
be set to that color.
|
||||
|
||||
If the prop is omitted, the default implementation is unchanged from previous
|
||||
versions.
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { BackstageIdentityApi } from '@backstage/core-plugin-api';
|
||||
import { BackstagePalette } from '@backstage/theme';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { ButtonProps as ButtonProps_2 } from '@material-ui/core/Button';
|
||||
import { CardHeaderProps } from '@material-ui/core/CardHeader';
|
||||
@@ -100,7 +101,7 @@ export type BottomLinkProps = {
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Breadcrumbs(props: Props_21): JSX.Element;
|
||||
export function Breadcrumbs(props: Props_20): JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export type BreadcrumbsClickableTextClassKey = 'root';
|
||||
@@ -157,7 +158,7 @@ export interface CodeSnippetProps {
|
||||
// Warning: (ae-missing-release-tag) "Content" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Content(props: PropsWithChildren<Props_14>): JSX.Element;
|
||||
export function Content(props: PropsWithChildren<Props_13>): JSX.Element;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "ContentHeaderProps" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
@@ -368,10 +369,8 @@ export function FeatureCalloutCircular(
|
||||
// @public (undocumented)
|
||||
export type FiltersContainerClassKey = 'root' | 'title';
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Gauge(props: Props_11): JSX.Element;
|
||||
export function Gauge(props: GaugeProps): JSX.Element;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
@@ -384,6 +383,27 @@ export type GaugeCardClassKey = 'root';
|
||||
// @public (undocumented)
|
||||
export type GaugeClassKey = 'root' | 'overlay' | 'circle' | 'colorUnknown';
|
||||
|
||||
// @public (undocumented)
|
||||
export type GaugeProps = {
|
||||
value: number;
|
||||
fractional?: boolean;
|
||||
inverse?: boolean;
|
||||
unit?: string;
|
||||
max?: number;
|
||||
getColor?: GaugePropsGetColor;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type GaugePropsGetColor = (args: GaugePropsGetColorOptions) => string;
|
||||
|
||||
// @public (undocumented)
|
||||
export type GaugePropsGetColorOptions = {
|
||||
palette: BackstagePalette;
|
||||
value: number;
|
||||
inverse?: boolean;
|
||||
max?: number;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export function GitHubIcon(props: IconComponentProps): JSX.Element;
|
||||
|
||||
@@ -393,7 +413,7 @@ export function GroupIcon(props: IconComponentProps): JSX.Element;
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Header(props: PropsWithChildren<Props_15>): JSX.Element;
|
||||
export function Header(props: PropsWithChildren<Props_14>): JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export type HeaderClassKey =
|
||||
@@ -484,7 +504,7 @@ export type IconLinkVerticalProps = {
|
||||
// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function InfoCard(props: Props_16): JSX.Element;
|
||||
export function InfoCard(props: Props_15): JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export type InfoCardClassKey =
|
||||
@@ -565,7 +585,7 @@ export type LifecycleClassKey = 'alpha' | 'beta';
|
||||
// Warning: (ae-missing-release-tag) "LinearGauge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function LinearGauge(props: Props_12): JSX.Element | null;
|
||||
export function LinearGauge(props: Props_11): JSX.Element | null;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "LinkType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -666,7 +686,7 @@ export type OverflowTooltipClassKey = 'container';
|
||||
// Warning: (ae-missing-release-tag) "Page" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Page(props: PropsWithChildren<Props_17>): JSX.Element;
|
||||
export function Page(props: PropsWithChildren<Props_16>): JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PageClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -771,7 +791,7 @@ export type SelectInputBaseClassKey = 'root' | 'input';
|
||||
// Warning: (ae-missing-release-tag) "Sidebar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function Sidebar(props: PropsWithChildren<Props_18>): JSX.Element;
|
||||
export function Sidebar(props: PropsWithChildren<Props_17>): JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SIDEBAR_INTRO_LOCAL_STORAGE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -1961,7 +1981,7 @@ export const SidebarSpacer: React_2.ComponentType<
|
||||
// Warning: (ae-missing-release-tag) "SignInPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function SignInPage(props: Props_19): JSX.Element;
|
||||
export function SignInPage(props: Props_18): JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SignInPageClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -2050,7 +2070,7 @@ export function StatusWarning(props: PropsWithChildren<{}>): JSX.Element;
|
||||
// Warning: (ae-missing-release-tag) "StructuredMetadataTable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function StructuredMetadataTable(props: Props_13): JSX.Element;
|
||||
export function StructuredMetadataTable(props: Props_12): JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "StructuredMetadataTableListClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -2132,7 +2152,7 @@ export type TabBarClassKey = 'indicator' | 'flexContainer' | 'root';
|
||||
// Warning: (ae-missing-release-tag) "TabbedCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function TabbedCard(props: PropsWithChildren<Props_20>): JSX.Element;
|
||||
export function TabbedCard(props: PropsWithChildren<Props_19>): JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "TabbedCardClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
||||
@@ -53,3 +53,9 @@ export const AbsoluteProgress = () => (
|
||||
<Gauge value={89.2} fractional={false} unit="m/s" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const StaticColor = () => (
|
||||
<div style={containerStyle}>
|
||||
<Gauge getColor={() => '#f0f'} value={0.5} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -56,16 +56,26 @@ describe('<Gauge />', () => {
|
||||
};
|
||||
|
||||
it('colors the progress correctly', () => {
|
||||
expect(getProgressColor(palette, 'Not a Number' as any)).toBe('#ddd');
|
||||
expect(getProgressColor(palette, 10)).toBe(error);
|
||||
expect(getProgressColor(palette, 50)).toBe(warning);
|
||||
expect(getProgressColor(palette, 90)).toBe(ok);
|
||||
expect(getProgressColor({ palette, value: 'Not a Number' as any })).toBe(
|
||||
'#ddd',
|
||||
);
|
||||
expect(getProgressColor({ palette, value: 10 })).toBe(error);
|
||||
expect(getProgressColor({ palette, value: 50 })).toBe(warning);
|
||||
expect(getProgressColor({ palette, value: 90 })).toBe(ok);
|
||||
});
|
||||
|
||||
it('colors the inverse progress correctly', () => {
|
||||
expect(getProgressColor(palette, 'Not a Number' as any)).toBe('#ddd');
|
||||
expect(getProgressColor(palette, 10, true)).toBe(ok);
|
||||
expect(getProgressColor(palette, 50, true)).toBe(warning);
|
||||
expect(getProgressColor(palette, 90, true)).toBe(error);
|
||||
expect(
|
||||
getProgressColor({
|
||||
palette,
|
||||
value: 'Not a Number' as any,
|
||||
inverse: true,
|
||||
}),
|
||||
).toBe('#ddd');
|
||||
expect(getProgressColor({ palette, value: 10, inverse: true })).toBe(ok);
|
||||
expect(getProgressColor({ palette, value: 50, inverse: true })).toBe(
|
||||
warning,
|
||||
);
|
||||
expect(getProgressColor({ palette, value: 90, inverse: true })).toBe(error);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { makeStyles, useTheme } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { BackstagePalette, BackstageTheme } from '@backstage/theme';
|
||||
import { Circle } from 'rc-progress';
|
||||
import React from 'react';
|
||||
|
||||
@@ -46,32 +46,45 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
{ name: 'BackstageGauge' },
|
||||
);
|
||||
|
||||
type Props = {
|
||||
/** @public */
|
||||
export type GaugeProps = {
|
||||
value: number;
|
||||
fractional?: boolean;
|
||||
inverse?: boolean;
|
||||
unit?: string;
|
||||
max?: number;
|
||||
getColor?: GaugePropsGetColor;
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
/** @public */
|
||||
export type GaugePropsGetColorOptions = {
|
||||
palette: BackstagePalette;
|
||||
value: number;
|
||||
inverse?: boolean;
|
||||
max?: number;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type GaugePropsGetColor = (args: GaugePropsGetColorOptions) => string;
|
||||
|
||||
const defaultGaugeProps = {
|
||||
fractional: true,
|
||||
inverse: false,
|
||||
unit: '%',
|
||||
max: 100,
|
||||
};
|
||||
|
||||
export function getProgressColor(
|
||||
palette: BackstageTheme['palette'],
|
||||
value: number,
|
||||
inverse?: boolean,
|
||||
max?: number,
|
||||
) {
|
||||
export const getProgressColor: GaugePropsGetColor = ({
|
||||
palette,
|
||||
value,
|
||||
inverse,
|
||||
max,
|
||||
}) => {
|
||||
if (isNaN(value)) {
|
||||
return '#ddd';
|
||||
}
|
||||
|
||||
const actualMax = max ? max : defaultProps.max;
|
||||
const actualMax = max ? max : defaultGaugeProps.max;
|
||||
const actualValue = inverse ? actualMax - value : value;
|
||||
|
||||
if (actualValue < actualMax / 3) {
|
||||
@@ -81,14 +94,15 @@ export function getProgressColor(
|
||||
}
|
||||
|
||||
return palette.status.ok;
|
||||
}
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export function Gauge(props: Props) {
|
||||
export function Gauge(props: GaugeProps) {
|
||||
const { getColor = getProgressColor } = props;
|
||||
const classes = useStyles(props);
|
||||
const theme = useTheme<BackstageTheme>();
|
||||
const { palette } = useTheme<BackstageTheme>();
|
||||
const { value, fractional, inverse, unit, max } = {
|
||||
...defaultProps,
|
||||
...defaultGaugeProps,
|
||||
...props,
|
||||
};
|
||||
|
||||
@@ -102,7 +116,7 @@ export function Gauge(props: Props) {
|
||||
percent={asPercentage}
|
||||
strokeWidth={12}
|
||||
trailWidth={12}
|
||||
strokeColor={getProgressColor(theme.palette, asActual, inverse, max)}
|
||||
strokeColor={getColor({ palette, value: asActual, inverse, max })}
|
||||
className={classes.circle}
|
||||
/>
|
||||
<div className={classes.overlay}>
|
||||
|
||||
@@ -97,3 +97,24 @@ export const LinkInFooter = () => (
|
||||
</Grid>
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
export const StaticColor = () => (
|
||||
<Wrapper>
|
||||
<Grid item>
|
||||
<GaugeCard getColor={() => '#f00'} title="Red" progress={0.5} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<GaugeCard getColor={() => '#0f0'} title="Green" progress={0.5} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<GaugeCard getColor={() => '#00f'} title="Blue" progress={0.5} />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<GaugeCard
|
||||
getColor={({ palette }) => palette.status.error}
|
||||
title="palette.status.error"
|
||||
progress={0.5}
|
||||
/>
|
||||
</Grid>
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { InfoCard, InfoCardVariants } from '../../layout/InfoCard';
|
||||
import { BottomLinkProps } from '../../layout/BottomLink';
|
||||
import { Gauge } from './Gauge';
|
||||
import { Gauge, GaugePropsGetColor } from './Gauge';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
@@ -28,6 +28,7 @@ type Props = {
|
||||
progress: number;
|
||||
inverse?: boolean;
|
||||
deepLink?: BottomLinkProps;
|
||||
getColor?: GaugePropsGetColor;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
@@ -46,7 +47,14 @@ const useStyles = makeStyles(
|
||||
/** @public */
|
||||
export function GaugeCard(props: Props) {
|
||||
const classes = useStyles(props);
|
||||
const { title, subheader, progress, inverse, deepLink, variant } = props;
|
||||
const { title, subheader, progress, inverse, deepLink, variant, getColor } =
|
||||
props;
|
||||
|
||||
const gaugeProps = {
|
||||
inverse,
|
||||
getColor,
|
||||
value: progress,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
@@ -56,7 +64,7 @@ export function GaugeCard(props: Props) {
|
||||
deepLink={deepLink}
|
||||
variant={variant}
|
||||
>
|
||||
<Gauge value={progress} inverse={inverse} />
|
||||
<Gauge {...gaugeProps} />
|
||||
</InfoCard>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -41,3 +41,9 @@ export const LowProgress = () => (
|
||||
<LinearGauge value={0.2} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const StaticColor = () => (
|
||||
<div style={containerStyle}>
|
||||
<LinearGauge getColor={() => '#f0f'} value={0.5} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -20,18 +20,19 @@ import Tooltip from '@material-ui/core/Tooltip';
|
||||
// @ts-ignore
|
||||
import { Line } from 'rc-progress';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { getProgressColor } from './Gauge';
|
||||
import { getProgressColor, GaugePropsGetColor } from './Gauge';
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
* Progress value between 0.0 - 1.0.
|
||||
*/
|
||||
value: number;
|
||||
getColor?: GaugePropsGetColor;
|
||||
};
|
||||
|
||||
export function LinearGauge(props: Props) {
|
||||
const { value } = props;
|
||||
const theme = useTheme<BackstageTheme>();
|
||||
const { value, getColor = getProgressColor } = props;
|
||||
const { palette } = useTheme<BackstageTheme>();
|
||||
if (isNaN(value)) {
|
||||
return null;
|
||||
}
|
||||
@@ -39,7 +40,12 @@ export function LinearGauge(props: Props) {
|
||||
if (percent > 100) {
|
||||
percent = 100;
|
||||
}
|
||||
const strokeColor = getProgressColor(theme.palette, percent, false, 100);
|
||||
const strokeColor = getColor({
|
||||
palette,
|
||||
value: percent,
|
||||
inverse: false,
|
||||
max: 100,
|
||||
});
|
||||
return (
|
||||
<Tooltip title={`${percent}%`}>
|
||||
<span>
|
||||
|
||||
@@ -17,5 +17,10 @@
|
||||
export { GaugeCard } from './GaugeCard';
|
||||
export type { GaugeCardClassKey } from './GaugeCard';
|
||||
export { Gauge } from './Gauge';
|
||||
export type {
|
||||
GaugeProps,
|
||||
GaugePropsGetColor,
|
||||
GaugePropsGetColorOptions,
|
||||
} from './Gauge';
|
||||
export type { GaugeClassKey } from './Gauge';
|
||||
export { LinearGauge } from './LinearGauge';
|
||||
|
||||
Reference in New Issue
Block a user