123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- import React, { Component } from 'react';
- import { SimpleTable, Container, TruncatedText, SVGIcon, Tooltip, Tags } from 'ca-ui-toolkit';
- import PropTypes from 'prop-types';
- import menuOverflow16 from '@ba-ui-toolkit/ba-graphics/dist/icons/overflow-menu--horizontal_16.svg';
- import './ListView.scss';
- const COL_LENGTH = 4;
- /*
- Use in HomeView.js
- import { ListView } from '../ListView/ListView.js';
- ...
- <div className='homeContentContainer' style={{ 'width': '100%' }}>
- <ListView height={<value calculation>} stringGetter={stringGetter} glassContext={glassContext} entries={this._formatAssets()} entryAssets={assets} allowUploadFiles={allowUploadFiles} homeView={homeView} stateId={stateId}/>
- */
- export class ListView extends Component {
- static propTypes = {
- /** Custom class name(s) */
- className: PropTypes.string,
- /** The glass context handed down */
- glassContext: PropTypes.object,
- /** A reference to the ES5 homeView object */
- homeView: PropTypes.object,
- /** A copy of the i18n object used to translate strings */
- stringGetter: PropTypes.object,
- /** A list of the list entries formatted properly for use from the ca-ui-toolkit */
- entries: PropTypes.array,
- /** A list of the list entries unformatted with all information. This is to be used by glassContext */
- entryAssets: PropTypes.array,
- /** a boolean showing whether or not something can be uploaded if there is no data */
- allowUploadFiles: PropTypes.bool,
- /** An id used to remove context menus for list entries */
- stateId: PropTypes.string,
- /** Height Value for SimpleTable Component */
- height: PropTypes.string.isRequired
- };
- static defaultProps = {
- entries: []
- }
- constructor(props) {
- super(props);
- }
- state = {
- data: [],
- headerData: [
- { label: '' },
- { label: '' },
- { label: '' },
- { label: '' }
- ],
- menuLoading: false
- };
- componentDidMount(){
- // Data preparation for rendering
- const { entries, stringGetter } = this.props;
- this.setState({ entries: entries });
- this.setState({ data: this.dataPrep(entries) });
- this.setState({ headerData: [
- { label: stringGetter.get('list_header_name') },
- { label: stringGetter.get('list_header_type') },
- { label: stringGetter.get('list_header_last_modified') },
- { label: '' }
- ] });
- }
- componentDidUpdate(prevProps) {
- // In case if entries removed, refresh the list
- if(prevProps.entries.length !== this.props.entries.length)
- this.setState({ data: this.dataPrep(this.props.entries) });
- else{
- for(let i = 0; i < this.props.entries.length; i++){
- if(prevProps.entries[i].label !== this.props.entries[i].label || prevProps.entries[i].date !== this.props.entries[i].date){
- this.setState({ data: this.dataPrep(this.props.entries) });
- break;
- }
- }
- }
- }
- // Handler for data preparation and formating
- dataPrep = (data) => {
- const result = data.map(element => [
- { label: element.label },
- { label: element.type },
- { label: element.date },
- { label: '' }
- ]);
- return result;
- }
- // Return the value in the designated table cell
- _getValue = (row, col) => {
- if (this.state.data.length > row && this.state.data[row].length > col) {
- return this.state.data[row][col].label;
- }
- return null;
- };
- // Function for rendering the table body
- _cellRenderer(row, col) {
- /*
- Three situations of cell content:
- - Text (Name, Last updated)
- - Asset tag (Type)
- - Overflow menu icon
- */
- // Must: check the length first -> row length are fixed before state updates (concurrency issue)
- if(row >= this.props.entryAssets.length)
- return;
- if(col === 0) {
- return (
- <TruncatedText
- tabIndex='0'
- onKeyUp={ (e) => { this._openEntryViaTabbing(e, row); }}
- value={this.state.data[row][col].label}
- title={this.state.data[row][col].label}
- location='end'
- className='cell_assetName'
- />
- );
- } else if (col === 1) {
- const typeName = this.state.data[row][col].label;
- const asset = this.props.entryAssets[row];
- let tagColor;
- let supportedtypeName = typeName ? typeName[0].toUpperCase() + typeName.slice(1).toLowerCase() : '';
- /**
- * dashboard/report/story => purple tags
- * exploration/notebooks = blue tags
- * data upload, data sets, data module, data = green tags
- * others = grey tags
- */
- if(asset.type === 'report' || asset.type === 'reportView' || asset.type === 'interactiveReport' || asset.type === 'powerPlay8Report' || (asset.type === 'exploration' && (!asset.tags || asset.tags[0] !== 'explore'))){
- tagColor = 'purple';
- }else if((asset.type === 'exploration' && asset.tags && asset.tags[0] === 'explore') || asset.type === 'jupyterNotebook'){
- tagColor = 'blue';
- }else if(asset.type === 'dataSet2' || asset.type === 'module' || asset.type === 'uploadedFile' || asset.type === 'URL'){
- tagColor = 'teal';
- // If it's data and only one word, make all lowercased according to design doc
- supportedtypeName = supportedtypeName && supportedtypeName.split(' ').length === 1? supportedtypeName.toLowerCase() : supportedtypeName;
- }else{
- tagColor = 'gray';
- }
- return (<Tooltip orient='right' title={supportedtypeName} delay>
- <Tags tags={[{ value: supportedtypeName, label: supportedtypeName, color: tagColor }]} fullWidth={true} removable={false} />
- </Tooltip>);
- } else if (col === 3) {
- return (
- <div role="menu" tabIndex='0' className="iconWrapper" onKeyUp={ (e) => { this._openActionMenu(e, row); }}>
- <Tooltip title={this.props.stringGetter.get('assetActionMenu')} orient="right" delay>
- <SVGIcon iconId={menuOverflow16.id} rotate={90} className='menuIcon' id={`menuIconRow_${row}`} onClick={(e) => { this._openActionMenu(e); }}/>
- </Tooltip>
- </div>
- );
- } else {
- return (
- <TruncatedText
- value={this.state.data[row][col].label}
- title={this.state.data[row][col].label}
- location='end'
- className='cell_lastModified'
- />
- );
- }
- }
- // Handler for waking the action menu while clicking the menu icon on each table row
- _openActionMenu(e, index=e.target.id.split('_')[1]) {
- e.stopPropagation();
- // If not a shift click, ctrl click or a right click or the user pressed enter on the context menu
- if((e.type == 'click' && !e.shiftKey && !e.ctrlKey && e.nativeEvent.which !== 3) || (e.type=='keyup' && e.keyCode === 13)) {
- this.setState({ menuLoading: true });
- e.persist();
- const { homeView, entryAssets } = this.props;
- let asset = entryAssets[index];
- if(homeView && homeView.requiresAssetVerification) {
- homeView.loadAssetContextMenu(asset, e).then(function() {
- this.setState({ menuLoading: false });
- }.bind(this));
- }
- }
- }
- // Handler to open the project via tabbing action
- _openEntryViaTabbing(e, index=e.target.id.split('_')[1]){
- e.stopPropagation();
- // If not a shift click, ctrl click or a right click or the user pressed enter on the context menu
- if((e.type == 'click' && !e.shiftKey && !e.ctrlKey && e.nativeEvent.which !== 3) || (e.type=='keyup' && e.keyCode === 13)) {
- e.persist();
- this._openEntry(index);
- }
- }
- // Handler for clicking the entry to open the detail page
- _openEntry(row){
- this.props.homeView.onTileClick(this.props.entryAssets[row]);
- }
- // Function used to render the table header
- _headerRenderer(col) {
- return (
- <div style={{ fontWeight: 'bold' }}>
- <TruncatedText
- value={this.state.headerData[col].label}
- location="end"
- />
- </div>
- );
- }
- render() {
- /*
- Dynamic allocation for width division to avoid horizontal scrolling
- Original Proportion in design spec is: 544:205:314
- If necessary, reduced by 15% to make sure that moreButton won't be jumped outside of the table
- */
- return (
- <Container gutter={[2, 0]} id="TableCaHome" style={{ 'padding': '0 !important' }}>
- <SimpleTable
- // eslint-disable-next-line react/no-string-refs
- ref='simpletable'
- height={this.props.height}
- rowLength={this.state.data.length}
- colToAddScopeRow={1}
- colLength={COL_LENGTH}
- cellRenderer={(row, col) => (
- <Container gutter={[1, 1]}>
- {this._cellRenderer(row, col)}
- </Container>
- )}
- headerRenderer={col => (
- <Container gutter={[1, 1]}>
- {this._headerRenderer(col)}
- </Container>
- )}
- onRowClick={row => this._openEntry(row) }
- />
- </Container>
- );
- }
- }
|