@material-ui/lab#Timeline TypeScript Examples
The following examples show how to use
@material-ui/lab#Timeline.
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: Desktop.tsx From aqualink-app with MIT License | 5 votes |
TimelineDesktop = ({
siteId,
loading,
displayAddButton,
surveys,
pointId,
pointName,
isAdmin,
timeZone,
}: TimelineProps) => {
const classes = useStyles();
const isSiteIdValid = typeof siteId === "number";
return (
<Timeline>
{displayAddButton && !loading && (
<TimelineItem className={classes.timelineItem}>
<TimelineOppositeContent
className={classNames(
classes.timelineOppositeContent,
classes.addNewButtonOpposite
)}
/>
<TimelineContent className={classes.addNewButtonWrapper}>
{isSiteIdValid && <AddButton siteId={siteId} />}
</TimelineContent>
</TimelineItem>
)}
{surveys.map((survey, index) => (
<TimelineItem
key={survey?.id || `loading-survey-${index}`}
className={classes.timelineItem}
>
<TimelineOppositeContent className={classes.timelineOppositeContent}>
<LoadingSkeleton
className={classes.dateSkeleton}
loading={loading}
variant="text"
width="30%"
lines={1}
>
{survey?.diveDate && (
<Typography variant="h6" className={classes.dates}>
{displayTimeInLocalTimezone({
isoDate: survey.diveDate,
format: "MM/DD/YYYY",
displayTimezone: false,
timeZone,
})}
</Typography>
)}
</LoadingSkeleton>
</TimelineOppositeContent>
<TimelineSeparator>
<hr className={classes.connector} />
<TimelineDot variant="outlined" className={classes.dot} />
<hr className={classes.connector} />
</TimelineSeparator>
<TimelineContent className={classes.surveyCardWrapper}>
<SurveyCard
pointId={pointId}
pointName={pointName}
isAdmin={isAdmin}
siteId={siteId}
survey={survey}
loading={loading}
/>
</TimelineContent>
</TimelineItem>
))}
</Timeline>
);
}
Example #2
Source File: Vulnerability.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
Vulnerability: React.FC = () => {
const { vulnerabilityId } = useParams();
const { apiGet, apiPut } = useAuthContext();
const [vulnerability, setVulnerability] = useState<VulnerabilityType>();
const [comment, setComment] = useState<string>('');
const [showCommentForm, setShowCommentForm] = useState<boolean>(false);
const [menuAnchor, setMenuAnchor] = React.useState<null | HTMLElement>(null);
const classes = useStyles();
const history = useHistory();
const formatDate = (date: string) => {
return format(parseISO(date), 'MM-dd-yyyy');
};
const fetchVulnerability = useCallback(async () => {
try {
const result = await apiGet<VulnerabilityType>(
`/vulnerabilities/${vulnerabilityId}`
);
setVulnerability(result);
} catch (e) {
console.error(e);
}
}, [vulnerabilityId, apiGet]);
const updateVulnerability = async (body: { [key: string]: string }) => {
try {
if (!vulnerability) return;
const res = await apiPut<VulnerabilityType>(
'/vulnerabilities/' + vulnerability.id,
{
body: body
}
);
setVulnerability({
...vulnerability,
state: res.state,
substate: res.substate,
actions: res.actions
});
} catch (e) {
console.error(e);
}
};
useEffect(() => {
fetchVulnerability();
}, [fetchVulnerability]);
if (!vulnerability) return <></>;
const references = vulnerability.references.map((ref) => ref);
if (vulnerability.cve)
references.unshift({
name: 'NIST National Vulnerability Database',
url: `https://nvd.nist.gov/vuln/detail/${vulnerability.cve}`,
source: '',
tags: []
});
const states = [
'unconfirmed',
'exploitable',
'false-positive',
'accepted-risk',
'remediated'
];
interface dnstwist {
'domain-name': string;
fuzzer: string;
'dns-a'?: string;
'dns-aaas'?: string;
'dns-mx'?: string;
'dns-ns'?: string;
'date-first-observed'?: string;
}
return (
<>
{/* <Alert severity="info">
This vulnerability is found on 17 domains you have access to.
</Alert> */}
<div className={classes.root}>
<p>
<Link
to="# "
onClick={() => history.goBack()}
className={classes.backLink}
>
<ChevronLeft
style={{
height: '100%',
verticalAlign: 'middle',
marginTop: '-2px'
}}
></ChevronLeft>
Go back
</Link>
</p>
<div className={classes.contentWrapper}>
<div className={classes.content}>
<div
className={classes.panel}
style={{
flex: '0 0 45%'
}}
>
<Paper classes={{ root: classes.cardRoot }}>
<div className={classes.title}>
<h4>{vulnerability.title}</h4>
<Button
aria-haspopup="true"
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
setMenuAnchor(event.currentTarget)
}
>
<Flag
style={{
fontSize: '14px',
color: '#A9AEB1',
marginRight: '5px'
}}
></Flag>
Mark Item <ArrowDropDown />
</Button>
<Menu
anchorEl={menuAnchor}
keepMounted
open={Boolean(menuAnchor)}
getContentAnchorEl={null}
onClose={() => setMenuAnchor(null)}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center'
}}
>
{states.map((state) => (
<MenuItem
key={state}
onClick={() => {
updateVulnerability({
substate: state
});
setMenuAnchor(null);
}}
style={{ outline: 'none' }}
>
{stateMap[state]}
</MenuItem>
))}
</Menu>
</div>
<Chip
style={{
marginLeft: '1.5rem'
}}
// icon={<Check></Check>}
label={`${vulnerability.state[0].toUpperCase()}${vulnerability.state.slice(
1
)} (${stateMap[vulnerability.substate]})`}
color={
vulnerability.state === 'open' ? 'secondary' : 'default'
}
/>
<div className={classes.inner}>
<div className={classes.section}>
<h4 className={classes.subtitle}>Description</h4>
{vulnerability.description}
</div>
<div className={classes.section}>
<h4 className={classes.subtitle}>References</h4>
{references &&
references.map((ref, index) => (
<p key={index}>
<a
href={ref.url}
target="_blank"
rel="noopener noreferrer"
>
{ref.name ? ref.name : ref.url}
</a>
{ref.tags.length > 0
? ' - ' + ref.tags.join(',')
: ''}
</p>
))}
</div>
{vulnerability.source === 'hibp' && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Data</h4>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Exposed Emails</TableCell>
<TableCell align="right">Breaches</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.keys(
vulnerability.structuredData['emails']
).map((keyName, keyIndex) => (
<TableRow key={keyName}>
<TableCell component="th" scope="row">
{keyName}
</TableCell>
<TableCell align="right">
{vulnerability.structuredData['emails'][
keyName
].join(', ')}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
{vulnerability.source === 'lookingGlass' && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Data</h4>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>First Seen</TableCell>
<TableCell align="right">Last Seen</TableCell>
<TableCell align="right">Vuln Name</TableCell>
<TableCell align="right">Type</TableCell>
</TableRow>
</TableHead>
<TableBody>
{vulnerability.structuredData['lookingGlassData'].map(
(col: any) => (
<TableRow key={col.right_name}>
<TableCell component="th" scope="row">
{formatDistanceToNow(
parseISO(col.firstSeen)
) + ' ago'}
</TableCell>
<TableCell align="right">
{formatDistanceToNow(parseISO(col.lastSeen)) +
' ago'}
</TableCell>
<TableCell align="right">
{col.right_name}
</TableCell>
<TableCell align="right">
{col.vulnOrMal}
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</div>
)}
{vulnerability.source === 'dnstwist' && (
<div className={classes.section}>
<h4 className={classes.subtitle}>Data</h4>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Domain Name</TableCell>
<TableCell>IP Address / A Record</TableCell>
<TableCell>MX Record</TableCell>
<TableCell>NS Record</TableCell>
<TableCell>Date Observed</TableCell>
<TableCell>Fuzzer</TableCell>
</TableRow>
</TableHead>
<TableBody>
{vulnerability.structuredData['domains'].map(
(dom: dnstwist) => (
<TableRow key={dom['domain-name']}>
<TableCell component="th" scope="row">
{dom['domain-name']}
</TableCell>
<TableCell>{dom['dns-a']}</TableCell>
<TableCell>{dom['dns-mx']}</TableCell>
<TableCell>{dom['dns-ns']}</TableCell>
<TableCell>
{dom['date-first-observed']}
</TableCell>
<TableCell>{dom['fuzzer']}</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</TableContainer>
</div>
)}
</div>
</Paper>
</div>
<div
className={classes.panel}
style={{
flex: '0 0 30%'
}}
>
<Paper className={classes.cardRoot}>
<div className={classes.inner}>
<div className={classes.section}>
<h2 className={classes.subtitle}>Team notes</h2>
<button
onClick={() => {
setShowCommentForm(!showCommentForm);
}}
className={classes.linkSmall}
>
Add new note
</button>
</div>
{showCommentForm && (
<div>
<TextareaAutosize
style={{
width: '100%',
padding: 10,
marginBottom: '20px'
}}
rowsMin={4}
placeholder="Leave a Note"
onChange={(e) => setComment(e.target.value)}
/>
<Button
onClick={() => {
updateVulnerability({
comment
});
setComment('');
setShowCommentForm(false);
}}
style={{
width: 150,
marginBottom: '20px'
}}
variant="contained"
color="secondary"
>
Save
</Button>
</div>
)}
{vulnerability.actions &&
vulnerability.actions
.filter((action) => action.type === 'comment')
.map((action, index) => (
<div className={classes.section} key={index}>
<h4
className={classes.subtitle}
style={{ fontSize: '16px', display: 'inline' }}
>
{action.userName}
</h4>
<span style={{ float: 'right', display: 'inline' }}>
{formatDistanceToNow(parseISO(action.date))} ago
</span>
<ReactMarkdown linkTarget="_blank">
{action.value || ''}
</ReactMarkdown>
</div>
))}
</div>
</Paper>
<Paper className={classes.cardRoot}>
<div className={classes.inner}>
<div className={classes.section}>
<h2 className={classes.subtitle}>Vulnerability History</h2>
</div>
<Timeline
style={{
position: 'relative',
marginLeft: '-90%'
}}
align="left"
>
{vulnerability.actions &&
vulnerability.actions
.filter(
(action) =>
action.type === 'state-change' && action.substate
)
.map((action, index) => (
<TimelineItem key={index}>
<TimelineSeparator>
<TimelineDot />
<TimelineConnector />
</TimelineSeparator>{' '}
<TimelineContent>
State {action.automatic ? 'automatically ' : ''}
changed to {action.state} (
{stateMap[action.substate!].toLowerCase()})
{action.userName ? ' by ' + action.userName : ''}{' '}
<br></br>
<span
style={{
color: '#A9AEB1'
}}
>
{formatDate(action.date)}
</span>
</TimelineContent>
</TimelineItem>
))}
<TimelineItem>
<TimelineSeparator>
<TimelineDot />
</TimelineSeparator>
<TimelineContent>
Vulnerability opened<br></br>
<span
style={{
color: '#A9AEB1'
}}
>
{formatDate(vulnerability.createdAt)}
</span>
</TimelineContent>
</TimelineItem>
</Timeline>
</div>
</Paper>
<Paper className={classes.cardRoot}>
<div className={classes.inner}>
<div className={classes.section}>
<h2 className={classes.subtitle}>Provenance</h2>
<p>
<strong>Root Domain: </strong>
{vulnerability.domain.fromRootDomain}
</p>
<p>
<strong>Subdomain: </strong>
{vulnerability.domain.name} (
{vulnerability.domain.subdomainSource})
</p>
{vulnerability.service && (
<p>
<strong>Service/Port: </strong>
{vulnerability.service.service
? vulnerability.service.service
: vulnerability.service.port}{' '}
({vulnerability.service.serviceSource})
</p>
)}
{vulnerability.cpe && (
<>
<p>
<strong>Product: </strong>
{vulnerability.cpe}
</p>
</>
)}
<p>
<strong>Vulnerability: </strong>
{vulnerability.title} ({vulnerability.source})
</p>
</div>
</div>
</Paper>
{vulnerability.source === 'hibp' && (
<Paper className={classes.cardRoot}>
<div className={classes.inner}>
<div className={classes.section}>
<h2 className={classes.subtitle}>Breaches</h2>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Breach Name</TableCell>
<TableCell align="right">Date Added</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.keys(vulnerability.structuredData['breaches'])
.sort(
(a, b) =>
parseISO(
vulnerability.structuredData['breaches'][b][
'AddedDate'
]
).getTime() -
parseISO(
vulnerability.structuredData['breaches'][a][
'AddedDate'
]
).getTime()
)
.map((keyName, keyIndex) => (
<TableRow key={keyName}>
<TableCell component="th" scope="row">
{keyName}
</TableCell>
<TableCell align="right">
{formatDistanceToNow(
parseISO(
vulnerability.structuredData['breaches'][
keyName
]['AddedDate']
)
) + ' ago'}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
</Paper>
)}
</div>
</div>
</div>
</div>
</>
);
}
Example #3
Source File: AdrMenu.tsx From log4brains with Apache License 2.0 | 4 votes |
export function AdrMenu({ adrs, currentAdrSlug, className, ...props }: Props) {
const classes = useStyles();
const [newAdrOpen, setNewAdrOpen] = React.useState(false);
const mode = React.useContext(Log4brainsModeContext);
if (adrs === undefined) {
return null; // Because inside a <Grow>
}
let lastDateString = "";
return (
<div className={clsx(className, classes.root)} {...props}>
{mode === Log4brainsMode.preview && (
<Dialog
open={newAdrOpen}
onClose={() => setNewAdrOpen(false)}
aria-labelledby="newadr-dialog-title"
aria-describedby="newadr-dialog-description"
>
<DialogTitle id="newadr-dialog-title">Create a new ADR</DialogTitle>
<DialogContent>
<DialogContentText id="newadr-dialog-description">
<Typography>
Run the following command in your terminal:
</Typography>
<pre>
<code className="hljs bash">log4brains adr new</code>
</pre>
<Typography>
This will create a new ADR from your template and will open it
in your editor.
<br />
Just press <code>Ctrl+S</code> to watch your changes here,
thanks to Hot Reload.
</Typography>
<Typography variant="body2" style={{ marginTop: 20 }}>
Would you have preferred to create a new ADR directly from here?
<br />
Leave a ? on{" "}
<MuiLink
href="https://github.com/thomvaill/log4brains/issues/9"
target="_blank"
rel="noopener"
>
this GitHub issue
</MuiLink>{" "}
then!
</Typography>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => setNewAdrOpen(false)}
color="primary"
autoFocus
>
OK
</Button>
</DialogActions>
</Dialog>
)}
<Timeline className={classes.timeline}>
{mode === Log4brainsMode.preview && (
<TimelineItem className={classes.timelineItem}>
<TimelineOppositeContent
classes={{ root: classes.timelineOppositeContentRootAdd }}
/>
<TimelineSeparator>
<Tooltip title="Create a new ADR">
<Fab
size="small"
color="primary"
aria-label="create a new ADR"
className={classes.newAdrFab}
onClick={() => setNewAdrOpen(true)}
>
<AddIcon />
</Fab>
</Tooltip>
<TimelineConnector />
</TimelineSeparator>
<TimelineContent />
</TimelineItem>
)}
{adrs.map((adr) => {
const currentDateString = moment(
adr.publicationDate || adr.creationDate
).format("MMMM|YYYY");
const dateString =
currentDateString === lastDateString ? "" : currentDateString;
lastDateString = currentDateString;
const [month, year] = dateString.split("|");
return (
<TimelineItem
key={adr.slug}
className={clsx(classes.timelineItem, {
[classes.selectedTimelineItem]: currentAdrSlug === adr.slug
})}
>
<TimelineOppositeContent
classes={{ root: classes.timelineOppositeContentRoot }}
>
<Typography variant="body2" className={classes.date}>
{month}
</Typography>
<Typography variant="body2" className={classes.date}>
{year}
</Typography>
</TimelineOppositeContent>
<TimelineSeparator>
<TimelineDot className={classes.timelineConnector} />
<TimelineConnector className={classes.timelineConnector} />
</TimelineSeparator>
<TimelineContent>
<div className={classes.timelineContentContainer}>
<Link href={`/adr/${adr.slug}`} passHref>
<MuiLink
className={clsx(classes.adrLink, {
[classes[
`${adr.status}Link` as keyof typeof classes
]]: true
})}
variant="body2"
>
<span className={classes.adrTitle}>
{adr.title || "Untitled"}
</span>
{adr.package ? (
<span className={classes.package}>
<CropFreeIcon
fontSize="inherit"
className={classes.icon}
/>{" "}
{adr.package}
</span>
) : null}
</MuiLink>
</Link>
<div>
<AdrStatusChip
status={adr.status}
className={classes.adrStatusChip}
/>
</div>
</div>
</TimelineContent>
</TimelineItem>
);
})}
<TimelineItem>
<TimelineOppositeContent
classes={{ root: classes.timelineStartOppositeContentRoot }}
/>
<TimelineSeparator>
<TimelineConnector />
<TimelineDot>
<EmojiFlagsIcon />
</TimelineDot>
</TimelineSeparator>
<TimelineContent />
</TimelineItem>
</Timeline>
</div>
);
}