-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #83 from mitaai/blms/dashboard-ui
#56 Dashboard UI updates, annotations list view
- Loading branch information
Showing
14 changed files
with
417 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
src/components/Dashboard/DashboardAnnotationList/DashboardAnnotationList.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* eslint-disable no-underscore-dangle */ | ||
import React, { useState, useEffect } from 'react'; | ||
import Link from 'next/link'; | ||
import { | ||
Badge, Card, Col, ListGroup, Row, Tab, Tabs, | ||
} from 'react-bootstrap'; | ||
import { format } from 'date-fns'; | ||
import LoadingSpinner from '../../LoadingSpinner'; | ||
import { getSharedAnnotations, getOwnAnnotations } from '../../../utils/annotationUtil'; | ||
import { getGroupNameById } from '../../../utils/groupUtil'; | ||
import { FirstNameLastInitial } from '../../../utils/nameUtil'; | ||
|
||
const DashboardAnnotationList = ({ | ||
session, | ||
alerts, | ||
setAlerts, | ||
tab, | ||
mode, | ||
}) => { | ||
const [groupState, setGroupState] = useState({}); | ||
const [key, setKey] = useState(tab || 'mine'); | ||
const [listLoading, setListLoading] = useState(true); | ||
const [annotations, setAnnotations] = useState([]); | ||
const limit = mode === 'dashboard' ? 10 : undefined; | ||
|
||
useEffect(() => { | ||
async function fetchData() { | ||
if (session && (session.user.groups || session.user.id)) { | ||
if (key === 'shared') { | ||
setAnnotations( | ||
await getSharedAnnotations(session.user.groups, limit) | ||
.then(setListLoading(false)) | ||
.catch((err) => setAlerts([...alerts, { text: err.message, variant: 'danger' }])), | ||
); | ||
} else if (key === 'mine') { | ||
setAnnotations( | ||
await getOwnAnnotations(session.user.id, limit) | ||
.then(setListLoading(false)) | ||
.catch((err) => setAlerts([...alerts, { text: err.message, variant: 'danger' }])), | ||
); | ||
} | ||
} | ||
} | ||
fetchData(); | ||
}, [key]); | ||
|
||
|
||
useEffect(() => { | ||
if (annotations) { | ||
const fetchGroupState = async () => { | ||
annotations.map((annotation) => annotation.permissions.groups.map(async (group) => { | ||
if (!groupState[group]) { | ||
setGroupState({ ...groupState, [group]: await getGroupNameById(group) }); | ||
} | ||
})); | ||
}; | ||
fetchGroupState(); | ||
} | ||
}, [annotations, groupState]); | ||
|
||
return ( | ||
<Card> | ||
<Card.Header> | ||
<Card.Title> | ||
{mode === 'dashboard' && ( | ||
<Link href="/annotations">Annotations</Link> | ||
)} | ||
{mode === 'list' && ( | ||
<>Annotations</> | ||
)} | ||
</Card.Title> | ||
<Tabs | ||
transition={false} | ||
style={{ justifyContent: 'flex-end', float: 'right', marginTop: '-2rem' }} | ||
activeKey={key} | ||
onSelect={(k) => setKey(k)} | ||
> | ||
<Tab eventKey="shared" title="Shared" /> | ||
<Tab eventKey="mine" title="Mine" /> | ||
</Tabs> | ||
</Card.Header> | ||
{listLoading && ( | ||
<LoadingSpinner /> | ||
)} | ||
{!listLoading && annotations && annotations.length > 0 && ( | ||
<> | ||
<ListGroup> | ||
{annotations.sort((a, b) => new Date(b.created) - new Date(a.created)).map( | ||
(annotation) => ( | ||
<ListGroup.Item key={annotation._id}> | ||
<Row> | ||
<Col className="ellipsis" xl={8}> | ||
<Link href={`/documents/${annotation.target.document.slug}?mine=${key === 'mine'}#${annotation._id}`}> | ||
{annotation.target.selector.exact} | ||
</Link> | ||
</Col> | ||
<Col className="text-right" xl={4}> | ||
<small style={{ whiteSpace: 'nowrap' }}>{format(new Date(annotation.created), 'Ppp')}</small> | ||
</Col> | ||
</Row> | ||
<Row> | ||
<Col className="paragraph-ellipsis"> | ||
{annotation.body.value} | ||
</Col> | ||
</Row> | ||
<Row> | ||
<Col> | ||
<small className="text-muted"> | ||
{annotation.target.document.title} | ||
{' ('} | ||
{FirstNameLastInitial(annotation.creator.name)} | ||
) | ||
{annotation.permissions.groups | ||
&& annotation.permissions.groups.length > 0 && ( | ||
<Badge | ||
variant="info" | ||
key={annotation.permissions.groups.sort()[0]} | ||
className="mr-2" | ||
> | ||
{groupState[annotation.permissions.groups.sort()[0]]} | ||
</Badge> | ||
)} | ||
</small> | ||
</Col> | ||
</Row> | ||
</ListGroup.Item> | ||
), | ||
)} | ||
</ListGroup> | ||
{mode === 'dashboard' && ( | ||
<Card.Footer style={{ fontWeight: 'bold', borderTop: 0 }} key="all-annotations"> | ||
<Link href={`/annotations?tab=${key}`} disabled> | ||
{`See all ${key === 'shared' ? key : 'created'} annotations...`} | ||
</Link> | ||
</Card.Footer> | ||
)} | ||
</> | ||
)} | ||
{!listLoading && (!annotations || annotations.length === 0) && ( | ||
<Card.Body> | ||
{`You have no ${key === 'shared' ? key : 'created'} annotations.`} | ||
</Card.Body> | ||
)} | ||
</Card> | ||
); | ||
}; | ||
|
||
export default DashboardAnnotationList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import DashboardAnnotationList from './DashboardAnnotationList'; | ||
|
||
export default DashboardAnnotationList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* eslint-disable no-underscore-dangle */ | ||
/* eslint-disable guard-for-in */ | ||
/* eslint-disable no-restricted-syntax */ | ||
import React, { useState, useContext, useEffect } from 'react'; | ||
import $ from 'jquery'; | ||
import { | ||
Nav, | ||
Row, | ||
Col, | ||
Navbar, | ||
Breadcrumb, | ||
Container, | ||
Button, | ||
OverlayTrigger, | ||
Popover, | ||
Form, | ||
Card, | ||
ButtonGroup, | ||
Badge, | ||
Spinner, | ||
} from 'react-bootstrap'; | ||
|
||
import DocumentFiltersContext from '../../contexts/DocumentFiltersContext'; | ||
import DocumentAnnotationsContext from '../../contexts/DocumentAnnotationsContext'; | ||
|
||
|
||
function HeatMap() { | ||
const lineHeight = 18; | ||
const scaleFactor = $('#document-container').height() / $('#document-card-container').height(); | ||
const minStrokeHeight = 1; | ||
const offsetTop = $('#document-container').offset() === undefined ? 0 : $('#document-container').offset().top; | ||
const grandularity = lineHeight * scaleFactor >= minStrokeHeight ? lineHeight : Math.ceil(minStrokeHeight / scaleFactor); | ||
const [channelAnnotations] = useContext(DocumentAnnotationsContext); | ||
const [documentFilters] = useContext(DocumentFiltersContext); | ||
const n = (Math.ceil($('#document-card-container').height() / grandularity)); | ||
const map = new Array(isNaN(n) ? 0 : n); | ||
|
||
for (const side in channelAnnotations) { | ||
if (channelAnnotations[side] !== null) { | ||
for (const anno of channelAnnotations[side]) { | ||
if (documentFilters.annotationIds[side] === null || documentFilters.annotationIds[side].includes(anno._id)) { | ||
if (anno.position.height !== undefined) { | ||
// now we have to convert the annotations position and height into starting and ending indexs for the map | ||
let startIndex = Math.floor((anno.position.top - offsetTop) / grandularity); | ||
startIndex = startIndex < 0 ? 0 : startIndex; | ||
const endIndex = Math.floor((anno.position.top + anno.position.height - offsetTop) / grandularity); | ||
for (let i = startIndex; i <= endIndex; i += 1) { | ||
if (map[i] === undefined) { | ||
map[i] = 0; | ||
} | ||
map[i] += 1; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
return ( | ||
<> | ||
<div id="heat-map" style={{ height: (map.length * lineHeight * scaleFactor) + 10 }}> | ||
{map.map((v, i) => <div className="stroke" style={{ height: lineHeight * scaleFactor, top: i * lineHeight * scaleFactor, opacity: v * 0.2 }} />)} | ||
</div> | ||
|
||
<style jsx global> | ||
{` | ||
#heat-map { | ||
margin-top: -8px; | ||
background: #007bff; | ||
position: absolute; | ||
right: 3px; | ||
width: 8px; | ||
} | ||
#heat-map .stroke { | ||
position: absolute; | ||
background: rgb(255, 255, 10); | ||
width: 100%; | ||
} | ||
`} | ||
</style> | ||
</> | ||
); | ||
} | ||
|
||
export default HeatMap; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import HeatMap from './HeatMap'; | ||
|
||
export default HeatMap; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.