date-fns#differenceInCalendarDays TypeScript Examples
The following examples show how to use
date-fns#differenceInCalendarDays.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: exposure.ts From protect-scotland with Apache License 2.0 | 6 votes |
getSelfIsolationRemainingDays = (
isolationDuration: number,
contacts?: CloseContact[]
) => {
const exposureDate = getExposureDate(contacts);
const remainingDays = exposureDate
? isolationDuration - differenceInCalendarDays(Date.now(), exposureDate)
: -1;
return remainingDays > 0 ? remainingDays : 0;
}
Example #2
Source File: exposure.ts From protect-scotland with Apache License 2.0 | 6 votes |
hasCurrentExposure = (
isolationDuration: number,
contacts?: CloseContact[]
) => {
if (!contacts || contacts.length === 0) {
return false;
}
const exposureDate = getExposureDate(contacts);
const daysDiff = differenceInCalendarDays(new Date(), exposureDate!);
return daysDiff < isolationDuration;
}
Example #3
Source File: PostDate.tsx From norfolkdevelopers-website with MIT License | 6 votes |
export default function PostDate({ date }: PostDateProps) {
const daysSincePosted = differenceInCalendarDays(new Date(), date);
if (daysSincePosted > 7) {
return <>on {dateFormat(date)}</>
}
return <span title={dateFormat(date)}>{formatDistance(date, new Date())} ago</span>
}
Example #4
Source File: datecalc.ts From calendar-hack with MIT License | 6 votes |
export function calcPlanDates(planWeeks: number, planEndsOn: Date): PlanDates {
const end = startOfDay(endOfWeek(planEndsOn, { weekStartsOn: 1 }));
const planStart = subDays(planEndsOn, planWeeks * 7 - 1);
const start = startOfWeek(planStart, { weekStartsOn: 1 });
const totalDays = 1 + differenceInCalendarDays(end, start);
if (0 !== totalDays % 7) {
throw new Error("total days %7 !==0: " + totalDays);
}
const weekCount = totalDays / 7;
let result = {
start: start,
planStartDate: planStart,
planEndDate: planEndsOn, // before or on race day
end: end, // race day or beyond
weekCount: weekCount
}
return result;
}
Example #5
Source File: date.ts From ngx-gantt with MIT License | 5 votes |
getDaysInQuarter() {
return differenceInCalendarDays(this.endOfQuarter().addSeconds(1).value, this.startOfQuarter().value);
}
Example #6
Source File: date.ts From ngx-gantt with MIT License | 5 votes |
getDaysInYear() {
return differenceInCalendarDays(this.endOfYear().addSeconds(1).value, this.startOfYear().value);
}
Example #7
Source File: NftWidget.hooks.ts From atlas with GNU General Public License v3.0 | 4 votes |
useNftWidget = (videoId?: string): UseNftWidgetReturn => {
const { activeMemberId } = useUser()
const { nft, nftStatus } = useNft(videoId ?? '', { pollInterval: POLL_INTERVAL })
const {
isOwner,
englishTimerState,
canWithdrawBid,
needsSettling,
auctionPlannedEndDate,
userBid,
startsAtDate,
isUserTopBidder,
userBidUnlockDate,
saleType,
startsAtBlock,
canChangeBid,
isUserWhitelisted,
plannedEndAtBlock,
hasTimersLoaded,
} = useNftState(nft)
const { bids: userBids } = useBids(
{
where: {
isCanceled_eq: false,
nft: { id_eq: nft?.id },
bidder: { id_eq: activeMemberId },
},
},
{
fetchPolicy: 'cache-and-network',
skip: !nft?.id || !activeMemberId,
onError: (error) =>
SentryLogger.error('Failed to fetch member bids', 'useNftState', error, {
data: {
nft: nft?.id,
member: activeMemberId,
},
}),
}
)
const unwithdrawnUserBids = userBids?.filter(
(bid) =>
bid.auction.auctionType.__typename === 'AuctionTypeOpen' &&
(nftStatus?.status !== 'auction' || bid.auction.id !== nftStatus.auctionId) &&
bid.auction.winningMemberId !== activeMemberId
)
const bidFromPreviousAuction = unwithdrawnUserBids?.[0]
const owner = nft?.ownerMember
const { url: ownerAvatarUri } = useMemberAvatar(owner)
const { url: topBidderAvatarUri } = useMemberAvatar(nftStatus?.status === 'auction' ? nftStatus.topBidder : undefined)
const { entries: nftHistory } = useNftHistoryEntries(videoId || null, { pollInterval: POLL_INTERVAL })
switch (nftStatus?.status) {
case 'auction': {
return {
ownerHandle: owner?.handle,
ownerAvatarUri,
isOwner,
needsSettling,
bidFromPreviousAuction,
nftStatus: {
...nftStatus,
startsAtDate,
canWithdrawBid,
canChangeBid,
englishTimerState,
auctionPlannedEndDate,
topBidderAvatarUri,
isUserTopBidder,
userBidUnlockDate,
startsAtBlock,
plannedEndAtBlock,
hasTimersLoaded,
auctionBeginsInDays: startsAtDate ? differenceInCalendarDays(startsAtDate, new Date()) : 0,
auctionBeginsInSeconds: startsAtDate ? differenceInSeconds(startsAtDate, new Date()) : 0,
topBidderHandle: nftStatus.topBidder?.handle,
userBidAmount: Number(userBid?.amount) || undefined,
isUserWhitelisted,
},
nftHistory,
saleType,
}
}
case 'buy-now':
return {
ownerHandle: owner?.handle,
ownerAvatarUri,
isOwner,
needsSettling,
bidFromPreviousAuction,
nftStatus: {
...nftStatus,
},
nftHistory,
saleType,
}
case 'idle':
return {
ownerHandle: owner?.handle,
ownerAvatarUri,
isOwner,
needsSettling,
bidFromPreviousAuction,
nftStatus: {
...nftStatus,
},
nftHistory,
saleType,
}
}
return null
}
Example #8
Source File: dashboard.tsx From protect-scotland with Apache License 2.0 | 4 votes |
Dashboard: FC = () => {
const {t} = useTranslation();
const {
initialised,
enabled,
status,
contacts,
getCloseContacts,
permissions,
readPermissions
} = useExposure();
const [appState] = useAppState();
const {checked, paused} = useReminder();
const navigation = useNavigation();
const {onboarded, setContext, loadAppData} = useApplication();
const {
isolationDuration,
isolationCompleteDuration,
latestVersion: appLatestVersion
} = useSettings();
const [refreshing, setRefreshing] = useState(false);
const {
focusRef: tourFocus,
focusA11yElement: focusTourElem
} = useA11yElement();
const {
focusRef: dashboardFocus,
focusA11yElement: focusDashboardElem
} = useA11yElement();
const isFocused = useIsFocused();
const messageOpacity = useRef(new Animated.Value(0)).current;
const contentOpacity = useRef(new Animated.Value(0)).current;
const gridOpacity = useRef(new Animated.Value(0)).current;
const exposureEnabled = useRef(enabled);
const bluetoothDisabled = useRef(
status.state === 'disabled' && status.type?.includes(StatusType.bluetooth)
);
const pushNotificationsDisabled = useRef(
permissions.notifications.status === 'not_allowed'
);
const [state, setState] = useState<{
stage: number;
exposurePrompt: boolean;
bluetoothPrompt: boolean;
pushNotificationsPrompt: boolean;
disabled: boolean;
current: string;
isolationMessage: string | null;
isolationComplete: boolean;
default: string;
messages: string[];
}>({
stage: onboarded ? -1 : 0,
exposurePrompt: false,
bluetoothPrompt: false,
pushNotificationsPrompt: false,
disabled: false,
current: t(
getMessage({
onboarded,
enabled,
status,
messages: t('dashboard:tour', {returnObjects: true}),
stage: onboarded ? -1 : 0,
paused
})
),
isolationMessage: null,
isolationComplete: false,
messages: t('dashboard:tour', {returnObjects: true}),
default: t('dashboard:message:standard')
});
const version = useVersion();
const resetToNormal = () =>
setState((s) => ({
...s,
isolationComplete: false,
isolationMessage: null
}));
const setExposed = () =>
setState((s) => ({
...s,
isolationComplete: false,
isolationMessage: t('dashboard:exposed')
}));
const setIsolationComplete = () =>
setState((s) => ({
...s,
isolationComplete: true,
isolationMessage: t('dashboard:isolationComplete')
}));
const processContactsForMessaging = async () => {
let currentStatus = null;
try {
currentStatus = await SecureStore.getItemAsync('niexposuredate');
} catch (err) {
await SecureStore.deleteItemAsync('niexposuredate');
console.log('processContactsForMessaging', err);
}
if (currentStatus) {
const daysDiff = differenceInCalendarDays(
new Date(),
new Date(Number(currentStatus))
);
const withIsolation = isolationDuration + isolationCompleteDuration;
if (daysDiff >= withIsolation) {
await SecureStore.deleteItemAsync('niexposuredate');
return resetToNormal();
}
if (daysDiff >= isolationDuration && daysDiff < withIsolation) {
return setIsolationComplete();
}
if (contacts && contacts.length > 0) {
return setExposed();
}
}
return resetToNormal();
};
const checkLatestExposure = async () => {
const latestExposure = getExposureDate(contacts);
if (latestExposure) {
await SecureStore.setItemAsync(
'niexposuredate',
String(latestExposure.getTime())
);
}
processContactsForMessaging();
};
const onRefresh = () => {
setRefreshing(true);
loadAppData().then(() => setRefreshing(false));
};
useEffect(() => {
onRefresh();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
getCloseContacts();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [status]);
useEffect(() => {
checkLatestExposure();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [contacts, status]);
useFocusEffect(
React.useCallback(() => {
if (!isFocused || appState !== 'active') {
return;
}
readPermissions();
}, [isFocused, appState, readPermissions])
);
useEffect(() => {
setState((s) => ({
...s,
current: t(
getMessage({
onboarded,
enabled,
status,
messages: state.messages,
stage: state.stage,
paused
})
)
}));
exposureEnabled.current = enabled;
bluetoothDisabled.current =
status.state === 'disabled' &&
status.type?.includes(StatusType.bluetooth);
pushNotificationsDisabled.current =
permissions.notifications.status === 'not_allowed';
if (!exposureEnabled.current && onboarded) {
setTimeout(() => {
if (!exposureEnabled.current) {
setState((s) => ({
...s,
exposurePrompt: true
}));
}
}, PROMPT_OFFSET);
} else if (bluetoothDisabled.current && onboarded) {
setTimeout(() => {
if (bluetoothDisabled.current) {
setState((s) => ({
...s,
bluetoothPrompt: true
}));
}
}, PROMPT_OFFSET);
} else if (pushNotificationsDisabled.current && onboarded) {
setTimeout(() => {
if (
pushNotificationsDisabled.current &&
exposureEnabled.current &&
!bluetoothDisabled.current
) {
setState((s) => ({
...s,
pushNotificationsPrompt: true
}));
}
}, PROMPT_OFFSET);
} else if (onboarded && exposureEnabled.current) {
setState((s) => ({
...s,
exposurePrompt: false
}));
}
setTimeout(() => checkLatestExposure(), 100);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enabled, onboarded, status, permissions]);
const animateTourIn = () => {
setState((s) => ({...s, disabled: true}));
Animated.parallel([
Animated.timing(messageOpacity, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: true
}),
Animated.timing(gridOpacity, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: true
})
]).start(() => {
setState((s) => ({...s, disabled: false}));
});
};
const animateTourOut = () => {
setState((s) => ({...s, disabled: true}));
Animated.parallel([
Animated.timing(messageOpacity, {
toValue: 0,
duration: ANIMATION_DURATION,
useNativeDriver: true
}),
Animated.timing(gridOpacity, {
toValue: 0,
duration: ANIMATION_DURATION,
useNativeDriver: true
})
]).start(() => {
if (state.stage < state.messages.length - 1) {
setState((s) => ({
...s,
stage: state.stage + 1,
current: getMessage({
onboarded,
enabled,
status,
messages: state.messages,
stage: state.stage + 1
})
}));
animateTourIn();
} else {
setState((s) => ({
...s,
stage: -1,
current: s.default
}));
setContext({onboarded: true});
animateDashboard();
}
});
};
const animateDashboard = () => {
setState((s) => ({...s, disabled: true}));
Animated.parallel([
Animated.timing(messageOpacity, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: true
}),
Animated.timing(contentOpacity, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: true
}),
Animated.timing(gridOpacity, {
toValue: 1,
duration: ANIMATION_DURATION,
useNativeDriver: true
})
]).start(() => {
AsyncStorage.setItem('scot.onboarded', 'true');
setState((s) => ({...s, disabled: false}));
});
};
useEffect(() => {
if (onboarded) {
setTimeout(() => animateDashboard(), 200);
} else {
setTimeout(() => animateTourIn(), 200);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (!state.disabled) {
focusTourElem();
}
}, [focusTourElem, state.disabled]);
useEffect(() => {
if (onboarded && !state.disabled) {
focusDashboardElem();
}
}, [focusDashboardElem, onboarded, state.disabled]);
const handleTour = () => {
animateTourOut();
};
if (!initialised || !checked) {
return (
<>
<Container center="both">
<ActivityIndicator color={colors.darkGrey} size="large" />
</Container>
</>
);
}
return (
<>
<Header />
<ScrollView
refreshControl={
<RefreshControl
refreshing={onboarded && refreshing}
onRefresh={onRefresh}
/>
}>
{onboarded &&
appLatestVersion &&
version &&
appLatestVersion !== version?.display && (
<View style={blockStyles.block}>
<NewVersionCard />
<Spacing s={16} />
</View>
)}
<Spacing s={onboarded ? 15 : 65} />
{!onboarded && state.stage > -1 && (
<>
<View style={styles.dots}>
{[-1, 0, 1, 2].map((x) => (
<Animated.View
key={`step-${x}`}
style={[
styles.dot,
{
backgroundColor:
state.stage > x
? colors.primaryPurple
: colors.lighterPurple
}
]}
/>
))}
</View>
<A11yView
ref={tourFocus}
accessible
accessibilityHint={
t('dashboard:tourA11y', {returnObjects: true})[state.stage]
}
/>
<Animated.View style={{opacity: messageOpacity}}>
<TouchableWithoutFeedback onPress={() => handleTour()}>
<Markdown markdownStyles={markDownStyles}>
{state.current}
</Markdown>
</TouchableWithoutFeedback>
<Spacing s={30} />
<ArrowLink
onPress={() => {
if (!state.disabled) {
handleTour();
}
}}
accessibilityHint={t('dashboard:tourActionHint')}
invert>
<Text variant="h3" color="pink" style={styles.nextLink}>
{t('dashboard:tourAction')}
</Text>
</ArrowLink>
</Animated.View>
</>
)}
{onboarded && state.isolationMessage && (
<>
<Animated.View
style={{
opacity: messageOpacity
}}>
<View accessible ref={dashboardFocus}>
<Markdown
markdownStyles={
state.isolationComplete
? markDownStyles
: markDownStylesExposed
}>
{state.isolationMessage}
</Markdown>
</View>
{!state.isolationComplete && (
<>
<Spacing s={30} />
<ArrowLink
onPress={() =>
navigation.navigate(ScreenNames.closeContact)
}
accessibilityHint={t('dashboard:exposedAction')}
invert>
<Text variant="h3" color="pink" style={styles.nextLink}>
{t('dashboard:tourAction')}
</Text>
</ArrowLink>
</>
)}
{state.isolationComplete && (
<>
<Spacing s={20} />
<Text style={blockStyles.block} inline color="darkGrey">
{t('dashboard:isolationCompleteSupplemental')}
</Text>
</>
)}
</Animated.View>
<Spacing s={30} />
<Animated.View
style={[{opacity: contentOpacity}, blockStyles.block]}>
<Message />
</Animated.View>
</>
)}
{onboarded && !state.isolationMessage && (
<Animated.View style={{opacity: messageOpacity}}>
<View accessible ref={dashboardFocus}>
<Markdown markdownStyles={markDownStyles}>
{state.current}
</Markdown>
</View>
{state.stage === -1 && !paused && (
<>
<Spacing s={20} />
<Text style={blockStyles.block} inline color="darkGrey">
{t(`dashboard:message:bluetooth:${Platform.OS}`)}
</Text>
</>
)}
{state.stage === -1 && paused && (
<>
<Spacing s={20} />
<Text style={blockStyles.block} inline color="darkGrey">
{t('dashboard:message:pausedSupplemental')}
</Text>
</>
)}
</Animated.View>
)}
<Spacing s={30} />
<Grid
onboarded={onboarded}
stage={state.stage}
opacity={gridOpacity}
onboardingCallback={() => handleTour()}
/>
{state.isolationMessage && <Spacing s={34} />}
{onboarded && !state.isolationMessage && (
<>
<Animated.View
style={[{opacity: contentOpacity}, blockStyles.block]}>
<Spacing s={30} />
<Message />
<Spacing s={16} />
<Message
image={RestrictionsImage}
markdown={t('restrictions:message')}
accessibilityLabel={t('restrictions:a11y:label')}
accessibilityHint={t('restrictions:a11y:hint')}
link={t('links:r')}
/>
<Spacing s={45} />
</Animated.View>
</>
)}
{onboarded && (
<Text variant="h4" color="primaryPurple" align="center">
{t('dashboard:thanks')}
</Text>
)}
<Spacing s={60} />
</ScrollView>
{checked && !paused && state.exposurePrompt && (
<ExposureNotificationsModal
isVisible={state.exposurePrompt}
onBackdropPress={() =>
setState((s) => ({...s, exposurePrompt: false}))
}
onClose={() => setState((s) => ({...s, exposurePrompt: false}))}
/>
)}
{checked && !paused && state.bluetoothPrompt && (
<BluetoothNotificationsModal
isVisible={state.bluetoothPrompt}
onBackdropPress={() =>
setState((s) => ({...s, bluetoothPrompt: false}))
}
onClose={() => setState((s) => ({...s, bluetoothPrompt: false}))}
/>
)}
{checked && !paused && state.pushNotificationsPrompt && (
<PushNotificationsModal
isVisible={state.pushNotificationsPrompt}
onBackdropPress={() =>
setState((s) => ({...s, pushNotificationsPrompt: false}))
}
onClose={() =>
setState((s) => ({...s, pushNotificationsPrompt: false}))
}
/>
)}
</>
);
}
Example #9
Source File: DomainDetails.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
DomainDetails: React.FC<Props> = (props) => {
const { domainId } = props;
const { getDomain } = useDomainApi(false);
const { user } = useAuthContext();
const [domain, setDomain] = useState<Domain>();
const classes = useStyles();
const history = useHistory();
const fetchDomain = useCallback(async () => {
try {
setDomain(undefined);
const result = await getDomain(domainId);
setDomain(result);
} catch (e) {
console.error(e);
}
}, [domainId, getDomain]);
useEffect(() => {
fetchDomain();
}, [fetchDomain]);
const webInfo = useMemo(() => {
if (!domain) {
return [];
}
const categoriesToProducts: Record<string, Set<string>> = {};
for (const service of domain.services) {
for (const product of service.products) {
const version = product.version ? ` ${product.version}` : '';
const value = product.name + version;
const name =
product.tags && product.tags.length > 0 ? product.tags[0] : 'Misc';
if (!categoriesToProducts[name]) {
categoriesToProducts[name] = new Set();
}
categoriesToProducts[name].add(value);
}
}
return Object.entries(categoriesToProducts).reduce(
(acc, [name, value]) => [
...acc,
{
label: name,
value: Array.from(value).join(', ')
}
],
[] as any
);
}, [domain]);
const overviewInfo = useMemo(() => {
if (!domain) {
return [];
}
const ret = [];
if (domain.ip) {
ret.push({
label: 'IP',
value: domain.ip
});
}
ret.push({
label: 'First Seen',
value: `${differenceInCalendarDays(
Date.now(),
parseISO(domain.createdAt)
)} days ago`
});
ret.push({
label: 'Last Seen',
value: `${differenceInCalendarDays(
Date.now(),
parseISO(domain.updatedAt)
)} days ago`
});
if (domain.country) {
ret.push({
label: 'Country',
value: domain.country
});
}
if (domain.cloudHosted) {
ret.push({
label: 'Cloud Hosted',
value: 'Yes'
});
}
ret.push({
label: 'Organization',
value: domain.organization.name
});
return ret;
}, [domain]);
const [hiddenRows, setHiddenRows] = React.useState<{
[key: string]: boolean;
}>({});
const formatBytes = (bytes: number, decimals = 2): string => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
};
const generateWebpageList = (tree: any, prefix = '') => {
return (
<List
className={`${classes.listRoot}${prefix ? ' ' + classes.nested : ''}`}
>
{Object.keys(tree).map((key) => {
const isWebpage =
'url' in tree[key] && typeof tree[key]['url'] === 'string';
if (!isWebpage) {
const newPrefix = prefix + '/' + key;
return (
<>
<ListItem
button
onClick={() => {
setHiddenRows((hiddenRows: any) => {
hiddenRows[newPrefix] =
newPrefix in hiddenRows ? !hiddenRows[newPrefix] : true;
return { ...hiddenRows };
});
}}
key={newPrefix}
>
<ListItemText primary={(prefix ? '' : '/') + key + '/'} />
{hiddenRows[newPrefix] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse
in={!hiddenRows[newPrefix]}
timeout="auto"
unmountOnExit
>
{generateWebpageList(tree[key], newPrefix)}
</Collapse>
</>
);
}
const page = tree[key] as Webpage;
const parsed = new URL(page.url);
const split = parsed.pathname
.replace(/\/$/, '') // Remove trailing slash
.split('/');
return (
<ListItem
button
divider={true}
key={page.url}
onClick={() => window.open(page.url, '_blank')}
>
<ListItemText
primary={(prefix ? '' : '/') + split.pop()}
secondary={
page.status + ' • ' + formatBytes(page.responseSize ?? 0, 1)
}
></ListItemText>
</ListItem>
);
})}
</List>
);
};
if (!domain) {
return null;
}
const url =
(domain.services.find((service) => service.port === 443)
? 'https://'
: 'http://') + domain.name;
const { webpages = [] } = domain;
webpages.sort((a, b) => (a.url > b.url ? 1 : -1));
const webpageTree = generateWebpageTree(webpages);
const webpageList = generateWebpageList(webpageTree);
return (
<Paper classes={{ root: classes.root }}>
<div className={classes.title}>
<h4>
<Link to={`/inventory/domain/${domain.id}`}>{domain.name}</Link>
</h4>
<a href={url} target="_blank" rel="noopener noreferrer">
<LinkOffIcon />
</a>
</div>
<div className={classes.inner}>
{overviewInfo.length > 0 && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Overview</h4>
<DefinitionList items={overviewInfo} />
</div>
)}
{webInfo.length > 0 && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Known Products</h4>
<DefinitionList items={webInfo} />
</div>
)}
{domain.vulnerabilities.length > 0 && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Vulnerabilities</h4>
<Accordion className={classes.accordionHeaderRow} disabled>
<AccordionSummary>
<Typography className={classes.accordionHeading}>
Title
</Typography>
<Typography className={classes.vulnDescription}>
Serverity
</Typography>
<Typography className={classes.vulnDescription}>
State
</Typography>
<Typography className={classes.vulnDescription}>
Created
</Typography>
</AccordionSummary>
</Accordion>
{domain.vulnerabilities.map((vuln) => (
<Accordion
className={classes.accordion}
key={vuln.id}
onClick={(event) => {
event.stopPropagation();
history.push('/inventory/vulnerability/' + vuln.id);
}}
>
<AccordionSummary>
<Typography className={classes.accordionHeading}>
{vuln.title}
</Typography>
<Typography className={classes.vulnDescription}>
{vuln.severity}
</Typography>
<Typography className={classes.vulnDescription}>
{vuln.state}
</Typography>
<Typography className={classes.vulnDescription}>
{vuln.createdAt
? `${differenceInCalendarDays(
Date.now(),
parseISO(vuln.createdAt)
)} days ago`
: ''}
</Typography>
</AccordionSummary>
</Accordion>
))}
</div>
)}
{domain.services.length > 0 && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Ports</h4>
<Accordion className={classes.accordionHeaderRow} disabled>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography className={classes.accordionHeading}>
Port
</Typography>
<Typography className={classes.accordionHeading}>
Products
</Typography>
<Typography className={classes.lastSeen}>Last Seen</Typography>
</AccordionSummary>
</Accordion>
{domain.services.map((service) => {
const products = service.products
.map(
(product) =>
product.name +
(product.version ? ` ${product.version}` : '')
)
.join(', ');
return (
<Accordion className={classes.accordion} key={service.id}>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography className={classes.accordionHeading}>
{service.port}
</Typography>
<Typography className={classes.accordionHeading}>
{products}
</Typography>
<Typography className={classes.lastSeen}>
{service.lastSeen
? `${differenceInCalendarDays(
Date.now(),
parseISO(service.lastSeen)
)} days ago`
: ''}
</Typography>
</AccordionSummary>
{service.products.length > 0 && (
<AccordionDetails>
<DefinitionList
items={[
{
label: 'Products',
value: products
},
{
label: 'Banner',
value:
(user?.userType === 'globalView' ||
user?.userType === 'globalAdmin') &&
service.banner
? service.banner
: 'None'
}
]}
/>
</AccordionDetails>
)}
</Accordion>
);
})}
</div>
)}
{domain.webpages?.length > 0 && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Site Map</h4>
{webpageList}
</div>
)}
</div>
</Paper>
);
}
Example #10
Source File: columns.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
createColumns = (updateVulnerability: any) =>
[
{
Header: 'Vulnerability',
accessor: 'title',
Cell: ({ value, row }: CellProps<Vulnerability>) =>
row.original.cve ? (
<a
href={`https://nvd.nist.gov/vuln/detail/${row.original.cve}`}
target="_blank"
rel="noopener noreferrer"
>
{value} {extLink}
</a>
) : (
<p>{row.original.title}</p>
),
width: 800,
Filter: ColumnFilter
},
{
Header: 'Severity',
id: 'severity',
accessor: ({ severity, substate }) => (
<span
style={{
borderBottom: `6px solid ${getSeverityColor({
id: severity ?? ''
})}`,
width: '80px'
}}
// className={substate === 'unconfirmed' ? classes.severity : undefined}
>
{severity}
</span>
),
width: 100,
Filter: selectFilter(['Low', 'Medium', 'High', 'Critical', 'None'])
},
{
Header: 'KEV',
accessor: 'isKev',
Cell: ({ value, row }: CellProps<Vulnerability>) =>
value ? (
<a
href={`https://www.cisa.gov/known-exploited-vulnerabilities-catalog`}
target="_blank"
rel="noopener noreferrer"
>
Yes {extLink}
</a>
) : (
<p>No</p>
),
width: 50,
Filter: selectFilter([
{ value: 'true', label: 'Yes' },
{ value: 'false', label: 'No' }
])
},
{
Header: 'Domain',
id: 'domain',
accessor: ({ domain }) => (
<Link to={`/inventory/domain/${domain?.id}`}>{domain?.name}</Link>
),
width: 800,
Filter: ColumnFilter
},
{
Header: 'Product',
id: 'cpe',
accessor: ({ cpe, service }) => {
const product =
service &&
service.products.find(
(product) => cpe && product.cpe && cpe.includes(product.cpe)
);
if (product)
return product.name + (product.version ? ' ' + product.version : '');
else return cpe;
},
width: 100,
Filter: ColumnFilter
},
{
Header: 'Days Open',
id: 'createdAt',
accessor: ({ createdAt, actions = [] }) => {
// Calculates the total number of days a vulnerability has been open
let daysOpen = 0;
let lastOpenDate = createdAt;
let lastState = 'open';
actions.reverse();
for (const action of actions) {
if (action.state === 'closed' && lastState === 'open') {
daysOpen += differenceInCalendarDays(
parseISO(action.date),
parseISO(lastOpenDate)
);
lastState = 'closed';
} else if (action.state === 'open' && lastState === 'closed') {
lastOpenDate = action.date;
lastState = 'open';
}
}
if (lastState === 'open') {
daysOpen += differenceInCalendarDays(
new Date(),
parseISO(lastOpenDate)
);
}
return daysOpen;
},
disableFilters: true
},
{
Header: 'Status',
id: 'state',
width: 100,
maxWidth: 200,
accessor: 'state',
Filter: selectFilter([
'open',
'open (unconfirmed)',
'open (exploitable)',
'closed',
'closed (false positive)',
'closed (accepted risk)',
'closed (remediated)'
]),
Cell: ({ row }: CellProps<Vulnerability>) => (
<Dropdown
id="state-dropdown"
name="state-dropdown"
onChange={(e) => {
updateVulnerability(row.index, {
substate: e.target.value
});
}}
value={row.original.substate}
style={{ display: 'inline-block', width: '200px' }}
>
<option value="unconfirmed">Open (Unconfirmed)</option>
<option value="exploitable">Open (Exploitable)</option>
<option value="false-positive">Closed (False Positive)</option>
<option value="accepted-risk">Closed (Accepted Risk)</option>
<option value="remediated">Closed (Remediated)</option>
</Dropdown>
)
},
{
Header: 'Details',
Cell: ({ row }: CellProps<Vulnerability>) => (
<Link
to={`/inventory/vulnerability/${row.original.id}`}
style={{
fontSize: '14px',
cursor: 'pointer',
color: '#484D51',
textDecoration: 'none'
}}
>
DETAILS
</Link>
),
disableFilters: true
}
] as Column<Vulnerability>[]