Skip to content

Commit

Permalink
Merge pull request Sage-Bionetworks#492 from OCEO-YJ/PORTALS-1021
Browse files Browse the repository at this point in the history
PORTALS-1021: Implemented Sorting Functionality for Download List
  • Loading branch information
leem42 authored Jun 8, 2020
2 parents ac464e5 + 70d89bb commit 6dab8c4
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 15 deletions.
240 changes: 225 additions & 15 deletions src/lib/containers/download_list/DownloadListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import AccessRequirementList, {
AccessRequirementListProps,
} from '../access_requirement_list/AccessRequirementList'

import {
faSortAmountDown,
faSortAmountUp,
} from '@fortawesome/free-solid-svg-icons'

library.add(faTrash)

type DownloadListTableData = {
Expand Down Expand Up @@ -62,6 +67,17 @@ export default function DownloadListTable(props: DownloadListTableProps) {
batchFileResult: undefined,
downloadList: undefined,
})

type SortedColumn = {
column: string
isDescending: boolean
}

const [sortedColumn, setSortedColumn] = useState<SortedColumn>({
column: '',
isDescending: false,
})

const [arPropsFromHasAccess, set_arPropsFromHasAccess] = useState<
AccessRequirementListProps | undefined
>()
Expand All @@ -81,11 +97,11 @@ export default function DownloadListTable(props: DownloadListTableProps) {
// Get owner ids from download list by filtering to items that have a file handle
// then map to ownerIds
const ownerIdsFromHeaders = references?.results
.filter((el) => el.createdBy)
.map((el) => el.createdBy)
.filter(el => el.createdBy)
.map(el => el.createdBy)
const ownerIdsFromFileHandles = requestedFiles
.filter((el) => el.fileHandle?.createdBy !== undefined)
.map((el) => el.fileHandle!.createdBy)
.filter(el => el.fileHandle?.createdBy !== undefined)
.map(el => el.fileHandle!.createdBy)

const ownerIds: string[] = []
if (ownerIdsFromFileHandles) {
Expand Down Expand Up @@ -131,14 +147,14 @@ export default function DownloadListTable(props: DownloadListTableProps) {
// which can be determined by whether the batchFileResult has a failure code for the
// corresponding download list item
const referenceCall: Reference[] = filesToDownload
.filter((el) => {
.filter(el => {
return (
batchFileResult.requestedFiles.find(
(batchFile) => batchFile.fileHandleId === el.fileHandleId,
batchFile => batchFile.fileHandleId === el.fileHandleId,
)!.failureCode !== undefined
)
})
.map((el) => {
.map(el => {
return { targetId: el.associateObjectId }
})
// entity header is used to get the names of the files that the user
Expand Down Expand Up @@ -189,6 +205,7 @@ export default function DownloadListTable(props: DownloadListTableProps) {
},
]
setIsLoading(true)

setFileBeingDeleted(fileHandleId)
try {
const downloadList = await deleteDownloadListFiles(list, token)
Expand All @@ -204,6 +221,107 @@ export default function DownloadListTable(props: DownloadListTableProps) {
}
}

const sortColumn = async (column: string) => {
try {
setIsLoading(true)

const isDescending =
column === sortedColumn.column ? !sortedColumn.isDescending : false

setSortedColumn({
column,
isDescending,
})

const filesToDownload = downloadList?.filesToDownload ?? []

filesToDownload.sort((itemA, itemB) => {
return sortDownLoadList(itemA, itemB, column, isDescending)
})
setData({
...data,
downloadList,
})
listUpdatedCallback?.()
} catch (err) {
console.error(err)
} finally {
setIsLoading(false)
}
}
const getFileHandleInfo = (item: FileHandleAssociation) => {
const fileResult = requestedFiles.find(
fileRes => fileRes.fileHandleId === item.fileHandleId,
)
const fileHandle = fileResult ? fileResult.fileHandle : undefined

let fileName: string | undefined = ''
let createdBy: string | undefined = ''
let createdOn: string | undefined = ''
let contentSize: number | undefined = undefined

if (fileHandle && item) {
fileName = fileHandle.fileName
createdBy = fileHandle.createdBy
createdOn = fileHandle.createdOn
contentSize = fileHandle.contentSize
} else {
const requestedFile = results.find(
req => req.id === item.associateObjectId,
)
if (requestedFiles) {
fileName = requestedFile?.name
createdBy = requestedFile?.createdBy
createdOn = requestedFile?.createdOn
}
}
createdBy = userProfiles.find(el => el.ownerId === createdBy)?.userName

return { fileName, createdBy, createdOn, contentSize }
}

const sortDownLoadList = (
itemA: FileHandleAssociation,
itemB: FileHandleAssociation,
column: string,
isDescending: boolean,
) => {
const {
fileName: fileName_A,
createdBy: createdBy_A,
createdOn: createdOn_A,
contentSize: contentSize_A,
} = getFileHandleInfo(itemA)

const {
fileName: fileName_B,
createdBy: createdBy_B,
createdOn: createdOn_B,
contentSize: contentSize_B,
} = getFileHandleInfo(itemB)

const direction = isDescending ? 1 : -1

switch (column) {
case 'file':
return fileName_B?.localeCompare(fileName_A!)! * direction
case 'createdBy':
return createdBy_B?.localeCompare(createdBy_A!)! * direction
case 'createdOn':
return createdOn_B?.localeCompare(createdOn_A!)! * direction
case 'size':
if (contentSize_A && !contentSize_B) {
return -1
} else if (contentSize_B && !contentSize_A) {
return 1
} else {
return (contentSize_B! - contentSize_A!) * direction
}
default:
return 1
}
}

const filesToDownload = downloadList?.filesToDownload ?? []
const results = references?.results ?? []
let numBytes = 0
Expand All @@ -227,17 +345,109 @@ export default function DownloadListTable(props: DownloadListTableProps) {
<ReactBootstrap.Table striped={true} responsive={true}>
<thead>
<tr>
<th>File Name</th>
<th>
File
<button
className={`sort SRC-primary-background-color-hover ${
sortedColumn.column === 'file'
? 'SRC-primary-background-color'
: ''
}`}
onClick={() => {
sortColumn('file')
}}
>
<FontAwesomeIcon
icon={
sortedColumn.column === 'file'
? sortedColumn.isDescending === false
? faSortAmountDown
: faSortAmountUp
: faSortAmountDown
}
color={sortedColumn.column === 'file' ? 'white' : ''}
/>
</button>
</th>
<th>Access</th>
<th>Created By</th>
<th>Created On</th>
<th>Size</th>
<th>
Created By
<button
className={`sort SRC-primary-background-color-hover ${
sortedColumn.column === 'createdBy'
? 'SRC-primary-background-color'
: ''
}`}
onClick={() => {
sortColumn('createdBy')
}}
>
<FontAwesomeIcon
icon={
sortedColumn.column === 'createdBy'
? sortedColumn.isDescending === false
? faSortAmountDown
: faSortAmountUp
: faSortAmountDown
}
color={sortedColumn.column === 'createdBy' ? 'white' : ''}
/>
</button>
</th>
<th>
Created On
<button
className={`sort SRC-primary-background-color-hover ${
sortedColumn.column === 'createdOn'
? 'SRC-primary-background-color'
: ''
}`}
onClick={() => {
sortColumn('createdOn')
}}
>
<FontAwesomeIcon
icon={
sortedColumn.column === 'createdOn'
? sortedColumn.isDescending === false
? faSortAmountDown
: faSortAmountUp
: faSortAmountDown
}
color={sortedColumn.column === 'createdOn' ? 'white' : ''}
/>
</button>
</th>
<th>
Size
<button
className={`sort SRC-primary-background-color-hover ${
sortedColumn.column === 'size'
? 'SRC-primary-background-color'
: ''
}`}
onClick={() => {
sortColumn('size')
}}
>
<FontAwesomeIcon
icon={
sortedColumn.column === 'size'
? sortedColumn.isDescending === false
? faSortAmountDown
: faSortAmountUp
: faSortAmountDown
}
color={sortedColumn.column === 'size' ? 'white' : ''}
/>
</button>
</th>
{/* th below is made for trash can icon but holds no content */}
<th />
</tr>
</thead>
<tbody className="download-list-table">
{filesToDownload.map((item) => {
{filesToDownload.map(item => {
let createdBy: string | undefined = ''
let createdOn: string | undefined = ''
let fileName: string | undefined = ''
Expand All @@ -248,7 +458,7 @@ export default function DownloadListTable(props: DownloadListTableProps) {
fileBeingDeleted === fileHandleId ? 'SRC-inactive-bg' : ''
// See if batch file results has this fileHandleId
const fileResult = requestedFiles.find(
(fileRes) => fileRes.fileHandleId === fileHandleId,
fileRes => fileRes.fileHandleId === fileHandleId,
)
const fileHandle = fileResult?.fileHandle
const canDownload = fileHandle !== undefined
Expand All @@ -265,15 +475,15 @@ export default function DownloadListTable(props: DownloadListTableProps) {
} else {
// file is not downloadable, only show its name from entity header info
const requestedFile = results.find(
(req) => req.id === item.associateObjectId,
req => req.id === item.associateObjectId,
)
fileName = requestedFile?.name
createdBy = requestedFile?.createdBy
createdOn = requestedFile?.createdOn
}
createdOn = moment(createdOn).format('L LT')
const userProfile = userProfiles.find(
(el) => el.ownerId === createdBy,
el => el.ownerId === createdBy,
)
return (
<tr className={isCurrentlyBeingDeletedClass} key={fileHandleId}>
Expand Down
3 changes: 3 additions & 0 deletions src/lib/style/components/_download-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
}
}
}
.sort {
padding-left: 5px;
}
.create-package-container {
display: flex;
padding: 8px;
Expand Down

0 comments on commit 6dab8c4

Please sign in to comment.