Skip to content

Commit 9656851

Browse files
committed
feat(CullingInfo): add culling info component
1 parent 884ad76 commit 9656851

File tree

7 files changed

+201
-0
lines changed

7 files changed

+201
-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: Culling information
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: ['CullingInformation']
14+
sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/CullingInfo/CullingInfo.md
15+
---
16+
17+
import CullingInformation from '@patternfly/react-component-groups/dist/dynamic/CullingInfo';
18+
19+
A **culling information** component displays a warning for when an object will become culled or stale. It can display this as a tooltip or text.
20+
21+
## Examples
22+
23+
### Basic culling information
24+
25+
A basic culling information example
26+
27+
```js file="./CullingInfoExample.tsx"
28+
29+
```
30+
31+
### Culling information with customized props
32+
33+
For further customization, you can choose to render the tooltip as a message beside the icon instead. And you can utilize all properties of the [Tooltip component](/components/tooltip), with the exception of `content`.
34+
35+
```js file="./CullingInfoCustomExample.tsx"
36+
37+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import CullingInformation from '@patternfly/react-component-groups/dist/dynamic/CullingInfo';
3+
4+
5+
export const CustomizedRenderExample: React.FunctionComponent = () => {
6+
const staleDate = new Date('Sun Jan 26 2020');
7+
const warningDate = new Date('Mon Feb 03 2025');
8+
const cullingDate = new Date('Fri Feb 07 2025');
9+
return <>
10+
<CullingInformation
11+
stale={staleDate}
12+
currDate={new Date()}
13+
culled={cullingDate}
14+
staleWarning={warningDate}
15+
render={({ msg }) => (<React.Fragment>{msg} Hello there. Last seen: {` `}</React.Fragment>)}>
16+
</CullingInformation>
17+
</>
18+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import CullingInformation from '@patternfly/react-component-groups/dist/dynamic/CullingInfo';
3+
4+
export const BasicExample: React.FunctionComponent = () => {
5+
const staleDate = new Date('Sun Jan 26 2020');
6+
const warningDate = new Date('Mon Feb 03 2025');
7+
const cullingDate = new Date('Fri Feb 07 2025');
8+
return <>
9+
<CullingInformation
10+
stale={staleDate}
11+
currDate={new Date()}
12+
culled={cullingDate}
13+
staleWarning={warningDate}>
14+
</CullingInformation>
15+
</>
16+
};
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React from 'react';
2+
import { ExclamationCircleIcon, ExclamationTriangleIcon } from '@patternfly/react-icons';
3+
import { Tooltip, TooltipProps } from '@patternfly/react-core';
4+
import clsx from 'clsx';
5+
import { createUseStyles } from 'react-jss';
6+
import { CullingDate, CullingInfo, calculateTooltip } from './CullingInfoUtils';
7+
8+
export type Render = (config: { msg: string }) => React.ReactElement<any, any> | null;
9+
10+
const useStyles = createUseStyles({
11+
inventoryCullingWarning: {
12+
color: 'var(--pf-v6-global--warning-color--200)',
13+
fontWeight: 'var(--pf-v6-global--FontWeight--bold)',
14+
svg: {
15+
marginRight: 'var(--pf-v5-global--spacer--sm)'
16+
}
17+
},
18+
inventoryCullingDanger: {
19+
color: 'var(--pf-v6-global--warning-color--200)',
20+
fontWeight: 'var(--pf-v6-global--FontWeight--bold)',
21+
svg: {
22+
marginRight: 'var(--pf-v6-global--spacer--sm)'
23+
}
24+
}
25+
});
26+
27+
export interface CullingInformation extends Omit<TooltipProps, 'content'> {
28+
/** Option to add custom css classes */
29+
className?: string;
30+
/** Warning date for when object becomes stale */
31+
staleWarning: CullingDate;
32+
/** Date when object becomes culled */
33+
culled: CullingDate;
34+
/** Date when object becomes stale */
35+
stale: CullingDate;
36+
/** Current date */
37+
currDate: CullingDate;
38+
/** Optional prop to add custom children */
39+
children?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | undefined;
40+
/** Option to add custom message ReactElement */
41+
render?: Render;
42+
}
43+
44+
const CullingInformation: React.FunctionComponent<CullingInformation> = ({
45+
culled = new Date(0),
46+
className,
47+
staleWarning = new Date(0),
48+
stale = new Date(0),
49+
currDate = new Date(0),
50+
children,
51+
render,
52+
...props
53+
}) => {
54+
const classes = useStyles();
55+
56+
if (new Date(currDate).valueOf() - new Date(stale).valueOf() < 0) {
57+
return render
58+
? render({
59+
msg: '',
60+
})
61+
: children || null;
62+
}
63+
64+
const { isWarn, isError, msg }: CullingInfo = calculateTooltip(culled, staleWarning, currDate);
65+
if (render) {
66+
return (
67+
<span
68+
className={clsx({ [classes.inventoryCullingWarning]: isWarn, [classes.inventoryCullingDanger]: isError }, className)}
69+
>
70+
{isWarn && <ExclamationTriangleIcon className={classes.inventoryCullingWarning}/>}
71+
{isError && <ExclamationCircleIcon />}
72+
{render({ msg })}
73+
</span>
74+
);
75+
}
76+
77+
return (
78+
<React.Fragment>
79+
<Tooltip {...props} content={msg} position="bottom">
80+
<span
81+
className={clsx({ [classes.inventoryCullingWarning]: isWarn, [classes.inventoryCullingDanger]: isError }, className)}
82+
>
83+
{isError && <ExclamationCircleIcon />}
84+
{isWarn && <ExclamationTriangleIcon />}
85+
{children}
86+
</span>
87+
</Tooltip>
88+
</React.Fragment>
89+
);
90+
};
91+
92+
export default CullingInformation;
93+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export type CullingDate = string | number | Date;
2+
3+
export interface CullingInfo {
4+
isWarn?: boolean;
5+
isError?: boolean;
6+
msg: string;
7+
}
8+
export type CalculateTooltip = (culled: CullingDate, warning: CullingDate, currDate: CullingDate) => CullingInfo;
9+
10+
export const seconds = 1000;
11+
export const minutes: number = seconds * 60;
12+
export const hours: number = minutes * 60;
13+
export const days: number = hours * 24;
14+
15+
export const calculateTooltip: CalculateTooltip = (culled, warning, currDate) => {
16+
const culledDate: Date = new Date(culled);
17+
const warningDate: Date = new Date(warning);
18+
const diffTime: number = new Date(currDate).valueOf() - warningDate.valueOf();
19+
const removeIn: number = Math.ceil((culledDate.valueOf() - new Date(currDate).valueOf()) / days);
20+
const msg = `System scheduled for inventory removal in ${removeIn} days`;
21+
if (diffTime >= 0) {
22+
return {
23+
isError: true,
24+
msg,
25+
};
26+
}
27+
28+
return {
29+
isWarn: true,
30+
msg,
31+
};
32+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from './CullingInfo';
2+
export * from './CullingInfo';

packages/module/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ export * from './ErrorStack';
6666
export { default as ErrorBoundary } from './ErrorBoundary';
6767
export * from './ErrorBoundary';
6868

69+
export { default as CullingInfo } from './CullingInfo';
70+
export * from './CullingInfo';
71+
6972
export { default as ColumnManagementModal } from './ColumnManagementModal';
7073
export * from './ColumnManagementModal';
7174

0 commit comments

Comments
 (0)