Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
# Sidenav top-level section
# should be the same for all markdown files
section: Component groups
subsection: Status and state indicators
# Sidenav secondary level section
# should be the same for all markdown files
id: Stale data warning
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
source: react
# If you use typescript, the name of the interface to display props for
# These are found through the sourceProps function provided in patternfly-docs.source.js
propComponents: ['StaleDataWarning']
sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/StaleDataWarning/StaleDataWarning.md
---

import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';

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.

## Examples

### Basic stale data warning example

A basic stale data warning component displays a warning icon with additional details in a tooltip, including a timeline for data removal.

```js file="./StaleDataWarningExample.tsx"

```

### Stale data warning with customized props

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`.

```js file="./StaleDataWarningCustomExample.tsx"

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';
import { Stack, StackItem } from '@patternfly/react-core';


export const CustomizedRenderExample: React.FunctionComponent = () => {
const staleDate = new Date('Sun Jan 26 2020');
const warningDate = new Date('Mon Feb 15 2025');
const cullingDate = new Date('Fri Feb 20 2025');
return <>
<Stack>
<StackItem>
<StaleDataWarning
stale={staleDate}
currDate={new Date()}
culled={cullingDate}
staleWarning={warningDate}
render={({ msg }) => (<React.Fragment>{msg}</React.Fragment>)}>
</StaleDataWarning>
</StackItem>

<StackItem>
<StaleDataWarning
stale={staleDate}
currDate={new Date()}
culled={new Date('Fri Feb 07 2024')}
staleWarning={new Date('Mon Feb 03 2024')}
render={() => (<React.Fragment>This is an error message where the item is overdue</React.Fragment>)}>
</StaleDataWarning>
</StackItem>
</Stack>



</>
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import StaleDataWarning from '@patternfly/react-component-groups/dist/dynamic/StaleDataWarning';
import { Stack, StackItem } from '@patternfly/react-core';

export const BasicExample: React.FunctionComponent = () => {
const staleDate = new Date('Sun Jan 26 2020');
const warningDate = new Date('Mon Feb 15 2025');
const cullingDate = new Date('Fri Feb 20 2025');
return <>
<Stack>
<StackItem>
<StaleDataWarning
stale={staleDate}
currDate={new Date()}
culled={cullingDate}
staleWarning={warningDate}>
</StaleDataWarning>
</StackItem>

<StackItem>
<StaleDataWarning
stale={staleDate}
currDate={new Date()}
culled={new Date('Fri Feb 17 2024')}
staleWarning={new Date('Mon Feb 5 2024')}
>
</StaleDataWarning>
</StackItem>
</Stack>


</>
};
130 changes: 130 additions & 0 deletions packages/module/src/StaleDataWarning/StaleDataWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React from 'react';
import { ExclamationCircleIcon, ExclamationTriangleIcon } from '@patternfly/react-icons';
import { Button, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
import clsx from 'clsx';
import { createUseStyles } from 'react-jss';

type Render = (config: { msg: string }) => React.ReactElement<any, any> | null;

Check warning on line 7 in packages/module/src/StaleDataWarning/StaleDataWarning.tsx

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

Unexpected any. Specify a different type

Check warning on line 7 in packages/module/src/StaleDataWarning/StaleDataWarning.tsx

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

Unexpected any. Specify a different type
type CullingDate = string | number | Date;

interface StaleDataInfo {
isWarn?: boolean;
isError?: boolean;
msg: string;
}

const seconds = 1000;
const minutes: number = seconds * 60;
const hours: number = minutes * 60;
const days: number = hours * 24;

type CalculateTooltip = (culled: CullingDate, warning: CullingDate, currDate: CullingDate) => StaleDataInfo;

const useStyles = createUseStyles({
inventoryCullingWarning: {
color: 'var(--pf-t--global--icon--color--status--warning--default)',
},
inventoryCullingDanger: {
color: 'var(--pf-t--global--icon--color--status--danger--default)',
},
iconMargin: {
marginRight: 'var(--pf-t--global--spacer--sm)'
},
messageFont: {
fontWeight: 'var(--pf-t--global--font--weight--body--bold)',
},
});

/** extends TooltipProps */
export interface StaleDataWarningProps extends Omit<TooltipProps, 'content'> {
/** Option to add custom css classes */
className?: string;
/** Warning date for when object becomes stale */
staleWarning: CullingDate;
/** Date when object becomes culled */
culled: CullingDate;
/** Date when object becomes stale */
stale: CullingDate;
/** Current date */
currDate: CullingDate;
/** Optional prop to add custom children */
children?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | undefined;

Check warning on line 51 in packages/module/src/StaleDataWarning/StaleDataWarning.tsx

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

Unexpected any. Specify a different type

Check warning on line 51 in packages/module/src/StaleDataWarning/StaleDataWarning.tsx

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

Unexpected any. Specify a different type
/** Option to add custom message ReactElement */
render?: Render;
/** Optional custom warning message */
message?: string;
/** Accessible label for the icon */
"aria-label"?: string;
}

const StaleDataWarning: React.FunctionComponent<StaleDataWarningProps> = ({
culled = new Date(0),
className,
staleWarning = new Date(0),
stale = new Date(0),
currDate = new Date(0),
children,
render,
message,
"aria-label": ariaLabel,
...props
}) => {
const classes = useStyles();

const calculateTooltip: CalculateTooltip = (culled, warning, currDate) => {
const culledDate: Date = new Date(culled);
const warningDate: Date = new Date(warning);
const diffTime: number = new Date(currDate).valueOf() - warningDate.valueOf();
const removeIn: number = Math.ceil((culledDate.valueOf() - new Date(currDate).valueOf()) / days);
const msg = message ? message : `System scheduled for inventory removal in ${removeIn} days`;
if (diffTime >= 0) {
return {
isError: true,
msg,
};
}

return {
isWarn: true,
msg,
};
};

if (new Date(currDate).valueOf() - new Date(stale).valueOf() < 0) {
return render
? render({
msg: '',
})
: children || null;
}

const { isWarn, isError, msg }: StaleDataInfo = calculateTooltip(culled, staleWarning, currDate);
if (render) {
return (
<span
className={clsx({ [classes.inventoryCullingWarning]: isWarn, [classes.inventoryCullingDanger]: isError }, className)}
>
{isWarn &&
<Icon status="warning"><ExclamationTriangleIcon className={clsx( classes.iconMargin )} aria-label={ariaLabel || "Warning"}/></Icon>
}
{isError &&
<Icon status="danger"><ExclamationCircleIcon className={clsx( classes.iconMargin )} aria-label={ariaLabel || "Danger"}/></Icon>
}
<span className={clsx( classes.messageFont )}>
{render({ msg })}
</span>
</span>
);
}

return (
<>
{isError && <Tooltip {...props} content={<div>{msg}</div>}><Button variant="plain" icon={<Icon status="warning"><ExclamationTriangleIcon/></Icon>} aria-label={ariaLabel || "Warning"} /></Tooltip>}
{isWarn && <Tooltip {...props} content={<div>{msg}</div>}><Button variant="plain" icon={<Icon status="danger"><ExclamationCircleIcon/></Icon>} aria-label={ariaLabel || "Danger"} /></Tooltip>}
{children}
</>
);
};

export default StaleDataWarning;

2 changes: 2 additions & 0 deletions packages/module/src/StaleDataWarning/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './StaleDataWarning';
export * from './StaleDataWarning';
3 changes: 3 additions & 0 deletions packages/module/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export * from './UnauthorizedAccess';
export { default as TagCount } from './TagCount';
export * from './TagCount';

export { default as StaleDataWarning } from './StaleDataWarning';
export * from './StaleDataWarning';

export { default as SkeletonTableHead } from './SkeletonTableHead';
export * from './SkeletonTableHead';

Expand Down
Loading