X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e25469d58a038391fa16184da4f7078a0eae805a..7444429308f438fb2e29188db8f208223ed39128:/src/components/data-explorer/data-explorer.tsx diff --git a/src/components/data-explorer/data-explorer.tsx b/src/components/data-explorer/data-explorer.tsx index f2fe3be27e..ded1b5e39c 100644 --- a/src/components/data-explorer/data-explorer.tsx +++ b/src/components/data-explorer/data-explorer.tsx @@ -3,193 +3,202 @@ // SPDX-License-Identifier: AGPL-3.0 import * as React from 'react'; -import { DataTable, DataTableProps, Column, ColumnsConfigurator } from "../../components/data-table"; -import { Typography, Grid, ListItem, Divider, List, ListItemIcon, ListItemText } from '@material-ui/core'; -import IconButton, { IconButtonProps } from '@material-ui/core/IconButton'; +import { DataTable, DataColumn, ColumnSelector, toggleSortDirection, SortDirection, resetSortDirection } from "../../components/data-table"; +import { Typography, Grid, Paper, Toolbar } from '@material-ui/core'; +import IconButton from '@material-ui/core/IconButton'; import MoreVertIcon from "@material-ui/icons/MoreVert"; -import Popover from '../popover/popover'; - -export interface DataItem { - name: string; - type: string; - owner: string; - lastModified: string; - fileSize?: number; - status?: string; -} +import TableSortLabel from '@material-ui/core/TableSortLabel'; +import { formatFileSize, formatDate } from '../../common/formatters'; +import { DataItem } from './data-item'; +import { mockAnchorFromMouseEvent } from '../popover/helpers'; +import ContextMenu from '../context-menu/context-menu'; +export interface DataExplorerContextActions { + onAddToFavourite: (dataIitem: DataItem) => void; + onCopy: (dataIitem: DataItem) => void; + onDownload: (dataIitem: DataItem) => void; + onMoveTo: (dataIitem: DataItem) => void; + onRemove: (dataIitem: DataItem) => void; + onRename: (dataIitem: DataItem) => void; + onShare: (dataIitem: DataItem) => void; +} interface DataExplorerProps { items: DataItem[]; onItemClick: (item: DataItem) => void; + contextActions: DataExplorerContextActions; } -type DataExplorerState = Pick, "columns">; +interface DataExplorerState { + columns: Array>; + contextMenu: { + anchorEl?: HTMLElement; + item?: DataItem; + }; +} class DataExplorer extends React.Component { - state: DataExplorerState = { - columns: [ - { - header: "Name", - selected: true, - render: item => ( - this.props.onItemClick(item)} - > - - {renderIcon(item)} - - - - {item.name} - - - - ) - }, - { - header: "Status", - selected: true, - render: item => ( - - {item.status || "-"} - - ) - }, - { - header: "Type", - selected: true, - render: item => ( - - {item.type} - - ) - }, - { - header: "Owner", - selected: true, - render: item => ( - - {item.owner} - - ) - }, - { - header: "File size", - selected: true, - render: ({ fileSize }) => ( - - {typeof fileSize === "number" ? formatFileSize(fileSize) : "-"} - - ) - }, - { - header: "Last modified", - selected: true, - render: item => ( - - {formatDate(item.lastModified)} - - ) - }, - { - header: "Actions", - key: "Actions", - selected: true, - configurable: false, - renderHeader: () => ( - - - - ), - render: item => ( - - - - {[ - { - icon: "fas fa-users", - label: "Share" - }, - { - icon: "fas fa-sign-out-alt", - label: "Move to" - }, - { - icon: "fas fa-star", - label: "Add to favourite" - }, - { - icon: "fas fa-edit", - label: "Rename" - }, - { - icon: "fas fa-copy", - label: "Make a copy" - }, - { - icon: "fas fa-download", - label: "Download" - }].map(renderAction) - } - < Divider /> - { - renderAction({ icon: "fas fa-trash-alt", label: "Remove" }) - } - - - - ) - } - ] + contextMenu: {}, + columns: [{ + name: "Name", + selected: true, + sortDirection: "asc", + onSortToggle: () => this.toggleSort("Name"), + render: item => this.renderName(item) + }, { + name: "Status", + selected: true, + render: item => renderStatus(item.status) + }, { + name: "Type", + selected: true, + render: item => renderType(item.type) + }, { + name: "Owner", + selected: true, + render: item => renderOwner(item.owner) + }, { + name: "File size", + selected: true, + render: item => renderFileSize(item.fileSize) + }, { + name: "Last modified", + selected: true, + onSortToggle: () => this.toggleSort("Last modified"), + render: item => renderDate(item.lastModified) + }, { + name: "Actions", + selected: true, + configurable: false, + renderHeader: () => null, + render: item => this.renderActions(item) + }] }; + contextMenuActions = [[{ + icon: "fas fa-users fa-fw", + name: "Share", + onClick: this.handleContextAction("onShare") + }, { + icon: "fas fa-sign-out-alt fa-fw", + name: "Move to", + onClick: this.handleContextAction("onMoveTo") + }, { + icon: "fas fa-star fa-fw", + name: "Add to favourite", + onClick: this.handleContextAction("onAddToFavourite") + }, { + icon: "fas fa-edit fa-fw", + name: "Rename", + onClick: this.handleContextAction("onRename") + }, { + icon: "fas fa-copy fa-fw", + name: "Make a copy", + onClick: this.handleContextAction("onCopy") + }, { + icon: "fas fa-download fa-fw", + name: "Download", + onClick: this.handleContextAction("onDownload") + }], [{ + icon: "fas fa-trash-alt fa-fw", + name: "Remove", + onClick: this.handleContextAction("onRemove") + } + ]]; + render() { - return ( + return + + + + + + - ); + onRowContextMenu={this.openItemMenuOnRowClick} /> + + ; } - toggleColumn = (column: Column) => { + toggleColumn = (column: DataColumn) => { const index = this.state.columns.indexOf(column); const columns = this.state.columns.slice(0); columns.splice(index, 1, { ...column, selected: !column.selected }); this.setState({ columns }); } -} -const formatDate = (isoDate: string) => { - const date = new Date(isoDate); - return date.toLocaleString(); -}; + renderName = (item: DataItem) => + this.props.onItemClick(item)}> + + {renderIcon(item)} + + + + {item.name} + + + -const formatFileSize = (size: number) => { - switch (true) { - case size > 1000000000000: - return `${size / 1000000000000} TB`; - case size > 1000000000: - return `${size / 1000000000} GB`; - case size > 1000000: - return `${size / 1000000} MB`; - case size > 1000: - return `${size / 1000} KB`; - default: - return `${size} B`; + renderActions = (item: DataItem) => + + this.openItemMenuOnActionsClick(event, item)}> + + + + + openItemMenuOnRowClick = (event: React.MouseEvent, item: DataItem) => { + event.preventDefault(); + this.setState({ + contextMenu: { + anchorEl: mockAnchorFromMouseEvent(event), + item + } + }); } -}; -const renderIcon = (DataItem: DataItem) => { - switch (DataItem.type) { + openItemMenuOnActionsClick = (event: React.MouseEvent, item: DataItem) => { + this.setState({ + contextMenu: { + anchorEl: event.currentTarget, + item + } + }); + } + + closeContextMenu = () => { + this.setState({ contextMenu: {} }); + } + + handleContextAction(action: keyof DataExplorerContextActions) { + return (item: DataItem) => { + this.closeContextMenu(); + this.props.contextActions[action](item); + }; + } + + toggleSort = (columnName: string) => { + this.setState({ + columns: this.state.columns.map((column, index) => + column.name === columnName ? toggleSortDirection(column) : resetSortDirection(column)) + }); + } + +} + +const renderIcon = (dataItem: DataItem) => { + switch (dataItem.type) { case "arvados#group": return ; case "arvados#groupList": @@ -199,21 +208,29 @@ const renderIcon = (DataItem: DataItem) => { } }; -const renderAction = (action: { label: string, icon: string }, index?: number) => ( - - - - - - {action.label} - - -); - -const ItemActionsTrigger: React.SFC = (props) => ( - - - -); +const renderDate = (date: string) => + + {formatDate(date)} + ; + +const renderFileSize = (fileSize?: number) => + + {formatFileSize(fileSize)} + ; + +const renderOwner = (owner: string) => + + {owner} + ; + +const renderType = (type: string) => + + {type} + ; + +const renderStatus = (status?: string) => + + {status || "-"} + ; export default DataExplorer;