Skip to content

Commit

Permalink
feat: theme support (#11)
Browse files Browse the repository at this point in the history
* fix: add global.css for themeing, update board and icons to use css modules

* fix: update board tooltip css

* fix: update loader css

* fix: update tooltip css

* fix: update chart css

* fix: update graph to use proper tick color and apply data attribute for theme

* fix: remove bad import

* fix: fix issues with styling and theming

* chore: update readme

* fix: prettier

---------

Co-authored-by: root <root@Tegia.localdomain>
  • Loading branch information
Wolftousen and root authored Aug 30, 2024
1 parent fb3eff7 commit f1cacce
Show file tree
Hide file tree
Showing 38 changed files with 398 additions and 308 deletions.
2 changes: 2 additions & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export const parameters = {
light: { ...themes.normal, appBg: 'white', appPreviewBg: 'white' },
},
};

import '../src/global.css';
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ These functions are just shortcuts to get a Date a certain number of days in the
| `metricThresholdSet` | false | This allows you to customize the metric thresholds used for determining the rank of each metric. You only have to override the ones you need. There are defaults based on the official DORA Report that are used when these are not supplied.<br>This takes in a `MetricThresholdSet` object which contains a `MetricThresholds` object for each metric.<br>The threshold values for `elite`, `high` and `medium` are measured in hours. `low` is considered anything longer than medium, so it is not able to be supplied as a value in this object. |
| `message` | false | This allows a parent component to display a custom message while it does something. This setting overrides `loading` and the no data state that happens if `data` is empty or the `api` returns no data. |
| `holidays` | false | This field allows you to specify holidays that your organization follows to exclude from the calculations for the components. |
| `theme` | false | This field allows you to supply the `Theme` (dark = 0, light = 1) to the chart for styling purposes. You can alternatively just make sure that `data-theme='light\|dark'` is used on an ancestor of the component. |

### Board Component Properties

Expand All @@ -157,6 +158,8 @@ These functions are just shortcuts to get a Date a certain number of days in the

### Trend Component Properties

- All the `Common Properties`

| Property | Required | Description |
| ---------------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `showIndividualTrends` | false | Enabling this property will show a line for each individual metric trend in addition to the overall DORA trend. |
Expand Down
46 changes: 0 additions & 46 deletions src/Boards/Board.css

This file was deleted.

68 changes: 41 additions & 27 deletions src/Boards/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { useEffect, useState } from 'react';
import './Board.css';
import styles from './board.module.css';
import { Tooltip } from 'react-tooltip';
import DeployFrequencyIcon from '../icons/DeploymentFrequencyIcon';
import ChangeLeadTimeIcon from '../icons/ChangeLeadTimeIcon';
import ChangeFailureRateIcon from '../icons/ChangeFailureRateIcon';
import RecoverTimeIcon from '../icons/RecoverTimeIcon';
import { BoardProps } from '../interfaces/propInterfaces';
import { BoardProps, Theme } from '../interfaces/propInterfaces';
import { DoraState } from '../interfaces/metricInterfaces';
import { boardName, defaultDoraState } from '../constants';
import { buildDoraState } from '../functions/metricFunctions';
import { buildNonGraphBody } from '../functions/chartFunctions';
import ScoreIcon from '../icons/ScoreIcon';
import MetricIcon from '../icons/MetricIcon';
import TrendIcon from '../icons/TrendIcon';

const Board: React.FC<BoardProps> = props => {
Expand Down Expand Up @@ -38,102 +38,116 @@ const Board: React.FC<BoardProps> = props => {
props.metricThresholdSet,
]);

const nonGraphBody = buildNonGraphBody(props, noData, boardName);
const nonGraphBody = buildNonGraphBody(
props,
noData,
boardName,
styles.messageContainer,
);

if (nonGraphBody) {
return nonGraphBody;
}

if (props.showTrends) {
return (
<div data-testid={boardName} className="board">
<div
data-testid={boardName}
className={styles.board}
data-theme={props.theme === Theme.Dark ? 'dark' : 'light'}
>
<TrendIcon
metric={state.deploymentFrequency}
metricTitle={'Deployment Frequency'}
alwaysShowDetails={props.alwaysShowDetails}
setTooltipContent={setTooltipContent}
>
<DeployFrequencyIcon color="#FFFFFF" />
<DeployFrequencyIcon />
</TrendIcon>
<TrendIcon
metric={state.changeLeadTime}
metricTitle={'Change Lead Time'}
alwaysShowDetails={props.alwaysShowDetails}
setTooltipContent={setTooltipContent}
>
<ChangeLeadTimeIcon color="#FFFFFF" />
<ChangeLeadTimeIcon />
</TrendIcon>
<TrendIcon
metric={state.changeFailureRate}
metricTitle={'Change Failure Rate'}
alwaysShowDetails={props.alwaysShowDetails}
setTooltipContent={setTooltipContent}
>
<ChangeFailureRateIcon color="#FFFFFF" />
<ChangeFailureRateIcon />
</TrendIcon>
<TrendIcon
metric={state.recoverTime}
metricTitle={'Recover Time'}
alwaysShowDetails={props.alwaysShowDetails}
setTooltipContent={setTooltipContent}
>
<RecoverTimeIcon color="#FFFFFF" />
<RecoverTimeIcon />
</TrendIcon>
{!props.alwaysShowDetails && (
<Tooltip
className="scoreTooltip"
className={styles.boardTooltip}
id="scoreTooltip"
border="1px solid white"
opacity="1"
classNameArrow={styles.boardTooltipArrow}
border="1px"
content={tooltipContent}
/>
)}
</div>
);
} else {
return (
<div data-testid={boardName} className="board">
<ScoreIcon
<div
data-testid={boardName}
className={styles.board}
data-theme={props.theme === Theme.Dark ? 'dark' : 'light'}
>
<MetricIcon
metric={state.deploymentFrequency}
metricTitle={'Deployment Frequency'}
alwaysShowDetails={props.alwaysShowDetails}
hideColors={props.hideColors}
setTooltipContent={setTooltipContent}
>
<DeployFrequencyIcon color="#FFFFFF" />
</ScoreIcon>
<ScoreIcon
<DeployFrequencyIcon />
</MetricIcon>
<MetricIcon
metric={state.changeLeadTime}
metricTitle={'Change Lead Time'}
alwaysShowDetails={props.alwaysShowDetails}
hideColors={props.hideColors}
setTooltipContent={setTooltipContent}
>
<ChangeLeadTimeIcon color="#FFFFFF" />
</ScoreIcon>
<ScoreIcon
<ChangeLeadTimeIcon />
</MetricIcon>
<MetricIcon
metric={state.changeFailureRate}
metricTitle={'Change Failure Rate'}
alwaysShowDetails={props.alwaysShowDetails}
hideColors={props.hideColors}
setTooltipContent={setTooltipContent}
>
<ChangeFailureRateIcon color="#FFFFFF" />
</ScoreIcon>
<ScoreIcon
<ChangeFailureRateIcon />
</MetricIcon>
<MetricIcon
metric={state.recoverTime}
metricTitle={'Recover Time'}
alwaysShowDetails={props.alwaysShowDetails}
hideColors={props.hideColors}
setTooltipContent={setTooltipContent}
>
<RecoverTimeIcon color="#FFFFFF" />
</ScoreIcon>
<RecoverTimeIcon />
</MetricIcon>
{!props.alwaysShowDetails && (
<Tooltip
className="scoreTooltip"
className={styles.boardTooltip}
id="scoreTooltip"
border="1px solid white"
classNameArrow={styles.boardTooltipArrow}
border="1px"
opacity="1"
content={tooltipContent}
/>
Expand Down
21 changes: 21 additions & 0 deletions src/Boards/board.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.board {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-evenly;
align-items: center;
color: var(--react-dora-charts-text-color);
}

.boardTooltip {
border: 1px solid var(--react-dora-charts-primary-color) !important;
background-color: var(--react-dora-charts-background-color) !important;
color: var(--react-dora-charts-text-color) !important;
}

.boardTooltipArrow {
border-right: 1px solid var(--react-dora-charts-primary-color) !important;
border-bottom: 1px solid var(--react-dora-charts-primary-color) !important;
}
36 changes: 24 additions & 12 deletions src/ChangeFailureRateGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import CustomLayeredBar from './CustomLayeredBar';
import { Tooltip } from 'react-tooltip';
import TooltipContent from './ToolTip/TooltipContent';
import { ChartProps } from './interfaces/propInterfaces';
import { ChartProps, Theme } from './interfaces/propInterfaces';
import { DoraRecord } from './interfaces/apiInterfaces';
import {
buildNonGraphBody,
Expand All @@ -20,6 +20,7 @@ import {
} from './functions/chartFunctions';
import { changeFailureRateName, millisecondsToDays } from './constants';
import { v4 as uuidv4 } from 'uuid';
import styles from './chart.module.css';

interface ProcessData {
date: number;
Expand Down Expand Up @@ -137,7 +138,12 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
[startDate, endDate],
);

const nonGraphBody = buildNonGraphBody(props, noData, changeFailureRateName);
const nonGraphBody = buildNonGraphBody(
props,
noData,
changeFailureRateName,
styles.messageContainer,
);

if (nonGraphBody) {
return nonGraphBody;
Expand All @@ -155,13 +161,13 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
{payload.repository}: {(payload.total * 100).toFixed(2)}%
</p>
{payload.successful > 0 && (
<span key={uuidv4()} className="toolTipSpan">
<span key={uuidv4()} className={styles.toolTipSpan}>
Successes:
{successUrls.map((url: string, index: number) => {
return (
<a
key={uuidv4()}
className="toolTipLink"
className={styles.toolTipLink}
target="_blank"
href={url}
>
Expand All @@ -174,13 +180,13 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
)}
{payload.failed > 0 && payload.successful > 0 && <br key={uuidv4()} />}
{payload.failed > 0 && (
<span key={uuidv4()} className="toolTipSpan">
<span key={uuidv4()} className={styles.toolTipSpan}>
Issues:
{failureUrls.map((url: string, index: number) => {
return (
<a
key={uuidv4()}
className="toolTipLink"
className={styles.toolTipLink}
target="_blank"
href={url}
>
Expand All @@ -200,8 +206,14 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
setTooltipContent(<TooltipContent body={body} title={title} />);
};

const tickColor = props.theme === Theme.Dark ? '#FFF' : '#000';

return (
<div data-testid={changeFailureRateName} className="chart-wrapper">
<div
data-testid={changeFailureRateName}
className={styles.chartWrapper}
data-theme={props.theme === Theme.Dark ? 'dark' : 'light'}
>
<ResponsiveContainer width="100%" height="100%">
<BarChart
width={500}
Expand All @@ -215,15 +227,15 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<YAxis
type="number"
tick={{ fill: '#FFFFFF' }}
tick={{ fill: tickColor }}
tickFormatter={tick => tick * 100 + '%'}
/>
<XAxis
padding={{ left: 9, right: 9 }}
dataKey="date"
tickSize={15}
type="number"
tick={{ fill: '#FFFFFF' }}
tick={{ fill: tickColor }}
ticks={ticks}
domain={[startDate.getTime(), endDate.getTime()]}
tickFormatter={formatDateTicks}
Expand All @@ -246,12 +258,12 @@ const ChangeFailureRateGraph: React.FC<ChartProps> = (props: ChartProps) => {
</BarChart>
</ResponsiveContainer>
<Tooltip
className="chartTooltip"
className={styles.chartTooltip}
delayHide={1000}
clickable={true}
classNameArrow="chartTooltipArrow"
classNameArrow={styles.chartTooltipArrow}
id="cfrTooltip"
border="1px solid white"
border="1px"
opacity="1"
content={tooltipContent}
/>
Expand Down
Loading

0 comments on commit f1cacce

Please sign in to comment.