Skip to content

Commit 07c541c

Browse files
feat(CullingInfo): add culling info component (#568)
* feat(CullingInfo): add culling info component * fix: use semantic tokens, fix styling, delete cullingInfoUtils * fix: fix font semantic token; put Icon in a Button * fix: put tooltip icon in a button * chore: cleanup styling * fix: attempt accessibility fix * Culling info suggestions (#606) * trying some things * some suggestions * fix(StaleDataWarning): rename CullingInfo to StaleDataWarning; fix wording * fix: package-lock * chore: fix capitalization --------- Co-authored-by: Nicole Thoen <[email protected]>
1 parent 57f9ce3 commit 07c541c

File tree

6 files changed

+241
-0
lines changed

6 files changed

+241
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
# Sidenav top-level section
3+
# should be the same for all markdown files
4+
section: Component groups
5+
subsection: Status and state indicators
6+
# Sidenav secondary level section
7+
# should be the same for all markdown files
8+
id: Stale data warning
9+
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
10+
source: react
11+
# If you use typescript, the name of the interface to display props for
12+
# These are found through the sourceProps function provided in patternfly-docs.source.js
13+
propComponents: ['StaleDataWarning']
14+
sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/StaleDataWarning/StaleDataWarning.md
15+
---
16+
17+
import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';
18+
19+
A **stale data warning** component displays a warning status when an object is stale and planned for removal. Additional warning details can be displayed as a tooltip or text label.
20+
21+
## Examples
22+
23+
### Basic stale data warning example
24+
25+
A basic stale data warning component displays a warning icon with additional details in a tooltip, including a timeline for data removal.
26+
27+
```js file="./StaleDataWarningExample.tsx"
28+
29+
```
30+
31+
### Stale data warning with customized props
32+
33+
Instead of sharing details in a tooltip, you can place a short message beside the icon. You can still utilize all properties of the [tooltip component](/components/tooltip), with the exception of `content`.
34+
35+
```js file="./StaleDataWarningCustomExample.tsx"
36+
37+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from 'react';
2+
import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';
3+
import { Stack, StackItem } from '@patternfly/react-core';
4+
5+
6+
export const CustomizedRenderExample: React.FunctionComponent = () => {
7+
const staleDate = new Date('Sun Jan 26 2020');
8+
const warningDate = new Date('Mon Feb 15 2025');
9+
const cullingDate = new Date('Fri Feb 20 2025');
10+
return <>
11+
<Stack>
12+
<StackItem>
13+
<StaleDataWarning
14+
stale={staleDate}
15+
currDate={new Date()}
16+
culled={cullingDate}
17+
staleWarning={warningDate}
18+
render={({ msg }) => (<React.Fragment>{msg}</React.Fragment>)}>
19+
</StaleDataWarning>
20+
</StackItem>
21+
22+
<StackItem>
23+
<StaleDataWarning
24+
stale={staleDate}
25+
currDate={new Date()}
26+
culled={new Date('Fri Feb 07 2024')}
27+
staleWarning={new Date('Mon Feb 03 2024')}
28+
render={() => (<React.Fragment>This is an error message where the item is overdue</React.Fragment>)}>
29+
</StaleDataWarning>
30+
</StackItem>
31+
</Stack>
32+
33+
34+
35+
</>
36+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';
3+
import { Stack, StackItem } from '@patternfly/react-core';
4+
5+
export const BasicExample: React.FunctionComponent = () => {
6+
const staleDate = new Date('Sun Jan 26 2020');
7+
const warningDate = new Date('Mon Feb 15 2025');
8+
const cullingDate = new Date('Fri Feb 20 2025');
9+
return <>
10+
<Stack>
11+
<StackItem>
12+
<StaleDataWarning
13+
stale={staleDate}
14+
currDate={new Date()}
15+
culled={cullingDate}
16+
staleWarning={warningDate}>
17+
</StaleDataWarning>
18+
</StackItem>
19+
20+
<StackItem>
21+
<StaleDataWarning
22+
stale={staleDate}
23+
currDate={new Date()}
24+
culled={new Date('Fri Feb 17 2024')}
25+
staleWarning={new Date('Mon Feb 5 2024')}
26+
>
27+
</StaleDataWarning>
28+
</StackItem>
29+
</Stack>
30+
31+
32+
</>
33+
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import React from 'react';
2+
import { ExclamationCircleIcon, ExclamationTriangleIcon } from '@patternfly/react-icons';
3+
import { Button, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
4+
import clsx from 'clsx';
5+
import { createUseStyles } from 'react-jss';
6+
7+
type Render = (config: { msg: string }) => React.ReactElement<any, any> | null;
8+
type CullingDate = string | number | Date;
9+
10+
interface StaleDataInfo {
11+
isWarn?: boolean;
12+
isError?: boolean;
13+
msg: string;
14+
}
15+
16+
const seconds = 1000;
17+
const minutes: number = seconds * 60;
18+
const hours: number = minutes * 60;
19+
const days: number = hours * 24;
20+
21+
type CalculateTooltip = (culled: CullingDate, warning: CullingDate, currDate: CullingDate) => StaleDataInfo;
22+
23+
const useStyles = createUseStyles({
24+
inventoryCullingWarning: {
25+
color: 'var(--pf-t--global--icon--color--status--warning--default)',
26+
},
27+
inventoryCullingDanger: {
28+
color: 'var(--pf-t--global--icon--color--status--danger--default)',
29+
},
30+
iconMargin: {
31+
marginRight: 'var(--pf-t--global--spacer--sm)'
32+
},
33+
messageFont: {
34+
fontWeight: 'var(--pf-t--global--font--weight--body--bold)',
35+
},
36+
});
37+
38+
/** extends TooltipProps */
39+
export interface StaleDataWarningProps extends Omit<TooltipProps, 'content'> {
40+
/** Option to add custom css classes */
41+
className?: string;
42+
/** Warning date for when object becomes stale */
43+
staleWarning: CullingDate;
44+
/** Date when object becomes culled */
45+
culled: CullingDate;
46+
/** Date when object becomes stale */
47+
stale: CullingDate;
48+
/** Current date */
49+
currDate: CullingDate;
50+
/** Optional prop to add custom children */
51+
children?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | undefined;
52+
/** Option to add custom message ReactElement */
53+
render?: Render;
54+
/** Optional custom warning message */
55+
message?: string;
56+
/** Accessible label for the icon */
57+
"aria-label"?: string;
58+
}
59+
60+
const StaleDataWarning: React.FunctionComponent<StaleDataWarningProps> = ({
61+
culled = new Date(0),
62+
className,
63+
staleWarning = new Date(0),
64+
stale = new Date(0),
65+
currDate = new Date(0),
66+
children,
67+
render,
68+
message,
69+
"aria-label": ariaLabel,
70+
...props
71+
}) => {
72+
const classes = useStyles();
73+
74+
const calculateTooltip: CalculateTooltip = (culled, warning, currDate) => {
75+
const culledDate: Date = new Date(culled);
76+
const warningDate: Date = new Date(warning);
77+
const diffTime: number = new Date(currDate).valueOf() - warningDate.valueOf();
78+
const removeIn: number = Math.ceil((culledDate.valueOf() - new Date(currDate).valueOf()) / days);
79+
const msg = message ? message : `System scheduled for inventory removal in ${removeIn} days`;
80+
if (diffTime >= 0) {
81+
return {
82+
isError: true,
83+
msg,
84+
};
85+
}
86+
87+
return {
88+
isWarn: true,
89+
msg,
90+
};
91+
};
92+
93+
if (new Date(currDate).valueOf() - new Date(stale).valueOf() < 0) {
94+
return render
95+
? render({
96+
msg: '',
97+
})
98+
: children || null;
99+
}
100+
101+
const { isWarn, isError, msg }: StaleDataInfo = calculateTooltip(culled, staleWarning, currDate);
102+
if (render) {
103+
return (
104+
<span
105+
className={clsx({ [classes.inventoryCullingWarning]: isWarn, [classes.inventoryCullingDanger]: isError }, className)}
106+
>
107+
{isWarn &&
108+
<Icon status="warning"><ExclamationTriangleIcon className={clsx( classes.iconMargin )} aria-label={ariaLabel || "Warning"}/></Icon>
109+
}
110+
{isError &&
111+
<Icon status="danger"><ExclamationCircleIcon className={clsx( classes.iconMargin )} aria-label={ariaLabel || "Danger"}/></Icon>
112+
}
113+
<span className={clsx( classes.messageFont )}>
114+
{render({ msg })}
115+
</span>
116+
</span>
117+
);
118+
}
119+
120+
return (
121+
<>
122+
{isError && <Tooltip {...props} content={<div>{msg}</div>}><Button variant="plain" icon={<Icon status="warning"><ExclamationTriangleIcon/></Icon>} aria-label={ariaLabel || "Warning"} /></Tooltip>}
123+
{isWarn && <Tooltip {...props} content={<div>{msg}</div>}><Button variant="plain" icon={<Icon status="danger"><ExclamationCircleIcon/></Icon>} aria-label={ariaLabel || "Danger"} /></Tooltip>}
124+
{children}
125+
</>
126+
);
127+
};
128+
129+
export default StaleDataWarning;
130+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from './StaleDataWarning';
2+
export * from './StaleDataWarning';

packages/module/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ export * from './UnauthorizedAccess';
1212
export { default as TagCount } from './TagCount';
1313
export * from './TagCount';
1414

15+
export { default as StaleDataWarning } from './StaleDataWarning';
16+
export * from './StaleDataWarning';
17+
1518
export { default as SkeletonTableHead } from './SkeletonTableHead';
1619
export * from './SkeletonTableHead';
1720

0 commit comments

Comments
 (0)