// Copyright (c) 2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import React, {Component} from 'react'; import styled from 'styled-components'; import moment from 'moment'; import LoadingDialog from './loading-dialog'; import {Button} from 'components/common/styled-components'; import CloudTile from './cloud-tile'; import {Base, ArrowLeft} from 'components/common/icons'; import ProviderModalContainer from './provider-modal-container'; import {FormattedMessage} from 'localization'; import {MapListItem, Provider} from 'cloud-providers'; const StyledProviderSection = styled.div.attrs({ className: 'provider-selection' })` display: flex; `; const StyledSpinner = styled.div` text-align: center; span { margin: 0 auto; } `; const StyledVisualizationSection = styled.div` display: flex; flex-direction: column; align-items: stretch; `; const StyledStorageHeader = styled.div` display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 16px; font-size: 12px; line-height: 14px; `; const StyledBackBtn = styled.a` margin-bottom: 16px; color: #3a414c; cursor: pointer; &:hover { font-weight: 500; } `; const StyledProviderVisSection = styled.div` flex: 1 1 auto; background-color: #f8f8f9; padding: 20px 24px; min-height: 280px; .title { font-size: 14px; line-height: 16px; font-weight: 500; margin-bottom: 16px; span { text-transform: capitalize; } } `; const StyledSeparator = styled.hr` border: solid #bfbfbf; border-width: 0 0 1px 0; margin-bottom: 16px; `; const StyledVisualizationList = styled.div` display: flex; flex-flow: row wrap; align-items: stretch; justify-content: space-between; `; const StyledVisualizationItem = styled.div` flex: 0 0 auto; width: 208px; display: flex; flex-direction: column; padding: 16px 8px; color: #3a414c; cursor: pointer; font-size: 12px; line-height: 18px; &:hover { .vis_item-icon, .vis_item-thumb, .vis_item-description, .vis_item-modification-date { opacity: 1; } } .vis_item-icon, .vis_item-thumb, .vis_item-description, .vis_item-modification-date { opacity: 0.9; transition: opacity 0.4s ease; } .vis_item-icon { position: relative; flex: 0 0 108px; background-color: #6a7484; border-radius: 4px; display: flex; flex-direction: row; align-items: center; justify-content: center; } .vis_item-thumb { position: relative; flex: 0 0 108px; background-size: cover; background-position: center; border-radius: 4px; } .vis_item-privacy { position: absolute; top: 0; left: 0; padding: 3px 6px; border-radius: 4px 0; background-color: rgba(58, 65, 76, 0.7); color: #fff; font-size: 11px; line-height: 18px; } .vis_item-title { margin-top: 16px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .vis_item-description { flex: 1 1 auto; margin-top: 8px; } .vis_item-modification-date { margin-top: 16px; flex: 1 0 auto; color: #6a7484; line-height: 15px; } `; type MapIconPorps = React.DetailedHTMLProps, HTMLDivElement>; const MapIcon: React.FC = props => { return (
{props.children}
); }; interface PrivacyBadgeProps { privateMap?: boolean; } const PrivacyBadge: React.FC = ({privateMap}) => ( {privateMap ? 'Private' : 'Public'} ); interface Visualization extends MapListItem { thumbnail?: Blob; } interface VisualizationItemProps { onClick?: React.MouseEventHandler; vis: Visualization; } const VisualizationItem: React.FC = ({vis, onClick}) => { return ( {vis.thumbnail ? (
{vis.hasOwnProperty('privateMap') ? : null}
) : ( {vis.hasOwnProperty('privateMap') ? : null} )} {vis.title} {vis.description && vis.description.length && ( {vis.description} )} Last modified {moment.utc(vis.lastModification).fromNow()}
); }; interface ProviderSelectProps { cloudProviders: Provider[]; onSelect: (name: string) => void; onSetCloudProvider: () => void; currentProvider?: string; } export const ProviderSelect: React.FC = ({ cloudProviders = [], onSelect, onSetCloudProvider, currentProvider }) => cloudProviders.length ? ( {cloudProviders.map(provider => ( onSelect(provider.name)} onSetCloudProvider={onSetCloudProvider} cloudProvider={provider} isSelected={provider.name === currentProvider} isConnected={Boolean(provider.getAccessToken && provider.getAccessToken())} /> ))} ) : (

No storage provider available

); interface LoadStorageMapProps { cloudProviders: Provider[]; onSetCloudProvider; currentProvider?: string; getSavedMaps: (provider?: Provider) => void; onLoadCloudMap: ({loadParams, provider}: {loadParams: any, provider: Provider}) => void; visualizations: Visualization[]; isProviderLoading?: boolean; } function LoadStorageMapFactory(): React.ComponentType { class LoadStorageMap extends Component { state = { showProviderSelect: true }; componentDidMount() { this._getSavedMaps(); } componentDidUpdate(prevProps) { if (prevProps.currentProvider !== this.props.currentProvider) { this._getSavedMaps(); } } _getProvider = () => { const {currentProvider, cloudProviders} = this.props; return (cloudProviders || []).find(p => p.name === currentProvider); }; _getSavedMaps() { const provider = this._getProvider(); if (provider) { this.props.getSavedMaps(provider); this.setState({showProviderSelect: false}); } } _onLoadCloudMap(provider: Provider | undefined, vis: Visualization) { this.props.onLoadCloudMap({ loadParams: vis.loadParams, provider }); } _clickBack = () => { this.setState({showProviderSelect: true}); }; _selectProvider = providerName => { this.props.onSetCloudProvider(providerName); const provider = (this.props.cloudProviders || []).find(p => p.name === providerName); this.props.getSavedMaps(provider); this.setState({showProviderSelect: false}); }; render() { const { visualizations, cloudProviders, currentProvider, isProviderLoading, onSetCloudProvider } = this.props; const provider = this._getProvider(); return ( {this.state.showProviderSelect ? ( ) : ( <> {isProviderLoading && ( )} {!isProviderLoading && visualizations && ( {provider?.getManagementUrl && ( )} {currentProvider} {visualizations.length ? ( visualizations.map(vis => ( this._onLoadCloudMap(provider, vis)} vis={vis} /> )) ) : (
)}
)} )}
); } } return LoadStorageMap; } export default LoadStorageMapFactory;