import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { QuickLaunch } from '../QuickLaunch/QuickLaunch.js'; import ReactHtmlParser from 'react-html-parser'; import { SVGIcon, ToggleSwitch, Tooltip } from 'ca-ui-toolkit'; import './HomeView.scss'; import { TilesView } from '../TilesView/TilesView.js'; import iconMap from '../utils/IconMap'; import grid16 from '@ba-ui-toolkit/ba-graphics/dist/icons/grid_16.svg'; import list32 from '@ba-ui-toolkit/ba-graphics/dist/icons/list_32.svg'; import dragdrop_icon from '../../../../../images/DragAndDrop.svg'; import ca_logoicon from '../../../../../images/ca_logoicon.png'; import noUpload from '../../../../../images/noUploadCapability.svg'; import { WelcomeView } from '../WelcomeView/WelcomeView'; import { ListView } from '../ListView/ListView.js'; export class HomeView extends Component { static propTypes = { /** Custom class name(s) */ className: PropTypes.string, /** An array of all of the tiles, if there are no assets it defaults to empty */ assets: PropTypes.array, /** A boolean which determines if a user can drag and drop uploads to quick launch */ allowUploadFiles: PropTypes.bool, /** A function which communicates with glass to upload the data from quick launch */ uploadFiles: PropTypes.func, /** A copy of the glass context */ glassContext: PropTypes.object, /** The strings used for the welcome label */ labels: PropTypes.object, /** A copy of the i18n translation object */ stringGetter: PropTypes.object, /** A reference to the ES5 homeView object */ homeView: PropTypes.object, /** a string used in the tiles to remove the context menu later */ stateId: PropTypes.string, /** The ID used to reference the file uploaded through Quick Launch */ quickLaunchCollectionId: PropTypes.string, /** The folder name in which to upload the file if a user runs QuickLaunch */ folderName: PropTypes.string, /** Specifies if a jupyter server is configured */ jupyterEnabled: PropTypes.string, /** The theme values from glass */ themeValues: PropTypes.object }; static defaultProps = { assets: [], allowUploadFiles: false } _quickRefCollectionId = 'com.ibm.bi.bahome_common.quickReferences'; state = { dragEnterTargets: [], tilesLoaded: false, showQuickLaunch: false, quickRefContent: '', assets: [], showWelcome: false, enableWelcome: false, showTile: true, listHeight: 550 } getTileAssets() { this._getMRUList() .then(function(mruList) { this.setState({ assets: mruList, tilesLoaded: true }); }.bind(this)); } constructor(props) { super(props); // Grab the quickLaunchTargets this.props.glassContext.appController.findCollection(this.props.quickLaunchCollectionId) .then(function (itemCollection) { this.quickLaunchItems = itemCollection || []; }.bind(this)); // Set up quick reference items this.quickRefItemData = { label: props.stringGetter.get('quickReference'), panels: [{ label: props.stringGetter.get('getStarted'), expanded: true, references:[] }, { label: props.stringGetter.get('sampleData'), expanded: false, references:[] }, { label: props.stringGetter.get('support'), expanded: false, references:[] }] }; this.props.glassContext.appController.findCollection(this._quickRefCollectionId) .then(function (refItems) { this.quickRefContentData = refItems; }.bind(this)); /** * Fetch assets to show on the Home page. */ this.getTileAssets(); } // Update local storage for the display of welcome section _toShowWelcomeAtLogin = (displayNextTime) => { const prefixID = this.localStorageIdentifier()+'_'; if(typeof(Storage)!=='undefined') window.localStorage.setItem(prefixID+'showWelcome', displayNextTime ? 'true' : 'false'); } // Update local storage for the display of tile or view _toShowTileViewAtLogin = (displayNextTime) => { const prefixID = this.localStorageIdentifier()+'_'; if(typeof(Storage)!=='undefined') window.localStorage.setItem(prefixID+'showTile', displayNextTime ? 'true' : 'false'); } componentDidMount(){ const prefixID = this.localStorageIdentifier()+'_'; if(typeof(Storage)!=='undefined'){ // Check local storage to determine whether welcome section should be displayed if(window.localStorage.getItem(prefixID+'showWelcome')){ // Not First time user this.setState({ showWelcome: window.localStorage.getItem(prefixID+'showWelcome')==='true' ? true : false }); }else{ // First time user window.localStorage.setItem(prefixID+'showWelcome', 'true'); this.setState({ showWelcome: true }); } // Check local storage to determine whether tile view or list view should be displayed if(window.localStorage.getItem(prefixID+'showTile')){ // Not First time user this.setState({ showTile: window.localStorage.getItem(prefixID+'showTile')==='true' ? true : false }); }else{ // First time user window.localStorage.setItem(prefixID+'showTile', 'true'); this.setState({ showTile: true }); } }else{ // local storage is not supported this.setState({ showWelcome: false, showTile: true }); } // Retrieve the admin's config context to determine whether welcome section should be shown this.props.glassContext.getCoreSvc('.Config').getConfigValue('Glass.welcomeScreenDisabled').then(state => { this.setState({ enableWelcome: (state.toString() !== 'true') ? true : false }, () => { if(!this.state.enableWelcome) this.setState({ showWelcome: false }); }); }); this._calculateListHeight(); window.addEventListener('resize', () => this._calculateListHeight()); } /** * Add an onClick listener for the 'browse' anchor tags. Uses a function from the AMD homeView object to upload. * Does this both for the 'Add some data' link and the 'Browse' link. */ componentDidUpdate() { const browseLinks = document.getElementsByClassName('homeBrowseFile'); for(let i = 0; i < browseLinks.length; i++) { let link = browseLinks[i]; link.onclick = function() { this.onBrowseFile(this.quickLaunchItems).bind(this); }.bind(this.props.homeView); } } componentWillUnmount(){ window.removeEventListener('resize', () => this._calculateListHeight()); } localStorageIdentifier = () => { return this.props.glassContext.profile.account.email; } _getContentService = () => { return this.props.glassContext.getSvc('.Content'); } _getMRUList = () => { return this.props.homeView._getMRUList(); } refreshMRUList = () => { return this._getContentService() .then(function(contentSvc) { // check if the refreshMRU method is available... if (contentSvc.refreshMRU) { return contentSvc.refreshMRU(); } return Promise.resolve(); }.bind(this)) .then(function(mruList) { // eslint-disable-line no-unused-vars this.getTileAssets(); // Note: May not need to call getTileAssets here, see if only need to do this.tiles = mruList; }.bind(this)); } /** * Formats the tile assets into the correct format to pass to the toolkit */ _formatAssets = () => { return this.props.homeView.formatAssetsInToolkitFormat(this.state.assets, iconMap); } _hasFiles(data) { if (data.types && data.types.length > 0) { if ((data.types.contains && data.types.contains('Files')) || (data.types.indexOf && data.types.indexOf('Files') >= 0)) { // IE11 or Chrome, Safari, Firefox return true; } } return false; } _getDataFromEvent(event) { if (event.originalEvent) { return event.originalEvent.dataTransfer; } else { return event.dataTransfer; } } _getName(glassContext) { const { account } = glassContext.profile; if (account && account.isAnonymous === true) { return null; } if (account && account.givenName) { return account.givenName; } else if (account && account.defaultName) { return account.defaultName; } return null; } _registerDragEnterEvent (target) { let state = this.state; state.dragEnterTargets.push(target); state.showQuickLaunch = true; this.setState(state); } _registerDragLeaveEvent (target) { let state = this.state; let targetsStillEntered = []; // See what targets you have left from dragging over and remove them from state let i; let oldTarget; for (i = 0; i < state.dragEnterTargets.length; i++) { oldTarget = state.dragEnterTargets[i]; if (oldTarget !== target) { targetsStillEntered.push(oldTarget); } } state.dragEnterTargets = targetsStillEntered; // If you are no longer hovering over items, hide the quick launch if (targetsStillEntered.length === 0) { state.showQuickLaunch = false; } this.setState(state); } hideQuickLaunch() { let state = this.state; state.dragEnterTargets = []; state.showQuickLaunch = false; this.setState(state); } _onDragOver (e) { e.preventDefault(); e.stopPropagation(); } _onDragEnter(e) { e.preventDefault(); e.stopPropagation(); // Retrieve the data file const data = this._getDataFromEvent(e); // Check if you can download if (this.props.allowUploadFiles && this._hasFiles(data)) { this._registerDragEnterEvent(e.target); } } _onDragLeave (e) { e.preventDefault(); e.stopPropagation(); if (this.props.allowUploadFiles) { this._registerDragLeaveEvent(e.target); } } _onDrop(e) { e.preventDefault(); e.stopPropagation(); let data = this._getDataFromEvent(e); if (this.props.allowUploadFiles && this._hasFiles(data)) { // Hide Quick Launch this.setState({ showQuickLaunch: false }); if (this.props.uploadFiles) { this.props.uploadFiles('drop', data.files, this.quickLaunchItems); } } } // Event handler to open the sample folder in the content nav (side-navbar) _openSamplesFolder = () => { const { homeView } = this.props; homeView._openSamples(); } _checkSamplesFolder = () => { const { homeView } = this.props; return homeView._checkSamplesFolder().then(function(status) { return status; }); } // Reformat the primary title to a DOM node by enforcing a new-line for brand name titleFormatter(brandText){ const { stringGetter } = this.props; let primaryTitleArray = stringGetter.get('welcome_primary_title', { 'brandName': brandText }).split(' '); return ReactHtmlParser(primaryTitleArray.join(' ')); } // Handler to switch the view mode via tabbing _switchModeViaTabbing = (e, mode) => { e.stopPropagation(); if((e.type == 'click' && !e.shiftKey && !e.ctrlKey && e.nativeEvent.which !== 3) || (e.type=='keyup' && e.keyCode === 13)) { e.persist(); if(mode==='tile'){ this._showTileView(); }else if(mode==='list'){ this._showListView(); } } } // Handler to enable the tile view _showTileView = () => { this._toShowTileViewAtLogin(true); this.setState({ showTile : true }); } // Handler to enable the list view _showListView = () => { this._toShowTileViewAtLogin(false); this.setState({ showTile : false }); } // Helper function to calculate the height of list view _calculateListHeight = () => { /* A little hacky trick used to determine the height of listView: 56: Margin-top of Welcome Header 64: Header Height 36: Margin-top of Recent Header while welcome is not shown 48: Height of Recent Header 20: Gap between Recent Header and Body 54: Recent View Footer 132: Calculated offset */ this.setState({ listHeight: window.innerHeight - 56 - 64 - 36 - 48 - 20 - 54 - 132 }); } render() { const { showQuickLaunch, assets, tilesLoaded } = this.state; const { glassContext, stringGetter, allowUploadFiles, folderName, homeView, stateId, quickLaunchCollectionId, jupyterEnabled, themeValues } = this.props; const wrapperClassName = showQuickLaunch ? 'homeViewWrapper dragging' : 'homeViewWrapper'; // Only render the main container once the tiles load, this makes it not look like it renders twice const tileContainer = tilesLoaded ? (