diff --git a/src/pages/Preferences/AWS/index.js b/src/pages/Preferences/AWS/index.js index 8b379114..45e66000 100644 --- a/src/pages/Preferences/AWS/index.js +++ b/src/pages/Preferences/AWS/index.js @@ -3,8 +3,10 @@ import ActiveList from '../../../panels/ActiveList'; import ButtonBar from '../../../panels/ButtonBar'; import Toolbar from '../../../panels/Toolbar'; import React from 'react'; +import EmptyPlaceholder from '../../../panels/EmptyPlaceholder'; import { breadcrumb } from '..'; +import theme from 'HPCCloudStyle/Theme.mcss'; import style from 'HPCCloudStyle/PageWithMenu.mcss'; import get from 'mout/src/object/get'; @@ -103,6 +105,29 @@ const AWSPrefs = React.createClass({ const { active, list, error, buttonsDisabled } = this.props; const activeData = active < list.length ? list[active] : null; + let content = null; + if (list.length) { + content = (
+ + +
); + } else { + content = ( + There are no EC2 Profiles available
+ You can create some with the above + } + />); + } + return (
-
- - -
+ { content }
); }, diff --git a/src/pages/Preferences/Cluster/index.js b/src/pages/Preferences/Cluster/index.js index 8cbb2045..61ef5a6d 100644 --- a/src/pages/Preferences/Cluster/index.js +++ b/src/pages/Preferences/Cluster/index.js @@ -3,10 +3,12 @@ import ClusterForm from './ClusterForm'; import ActiveList from '../../../panels/ActiveList'; import Toolbar from '../../../panels/Toolbar'; import ButtonBar from '../../../panels/ButtonBar'; +import EmptyPlaceholder from '../../../panels/EmptyPlaceholder'; import PresetSelector from '../PresetSelector'; import React from 'react'; import { breadcrumb } from '..'; +import theme from 'HPCCloudStyle/Theme.mcss'; import style from 'HPCCloudStyle/PageWithMenu.mcss'; import get from 'mout/src/object/get'; @@ -43,6 +45,7 @@ const ClusterPrefs = React.createClass({ simulations: React.PropTypes.object, taskflows: React.PropTypes.array, buttonsDisabled: React.PropTypes.bool, + onUpdateItem: React.PropTypes.func, onActiveChange: React.PropTypes.func, onApplyPreset: React.PropTypes.func, @@ -130,6 +133,35 @@ const ClusterPrefs = React.createClass({ const { active, list, error, buttonsDisabled, presetNames } = this.props; const activeData = active < list.length ? list[active] : null; + let content = null; + if (list && list.length) { + content = (
+ + + + +
); + } else { + content = ( + There are no Clusters available
+ You can create some with the above + } + />); + } + return (
-
- - - - -
+ { content }
); }, diff --git a/src/pages/Project/All/index.js b/src/pages/Project/All/index.js index 0dba9d7f..353b91fc 100644 --- a/src/pages/Project/All/index.js +++ b/src/pages/Project/All/index.js @@ -1,9 +1,10 @@ import merge from 'mout/src/object/merge'; import React from 'react'; import TableListing from '../../../panels/TableListing'; +import EmptyPlaceholder from '../../../panels/EmptyPlaceholder'; import { ProjectHelper } from '../../../utils/AccessHelper'; -import breadCrumbStyle from 'HPCCloudStyle/Theme.mcss'; +import theme from 'HPCCloudStyle/Theme.mcss'; import { connect } from 'react-redux'; import { dispatch } from '../../../redux'; @@ -57,13 +58,23 @@ const ProjectAll = React.createClass({ breadcrumb={{ paths: ['/'], icons: [ - breadCrumbStyle.breadCrumbRootIcon, + theme.breadCrumbRootIcon, ] }} location={ this.props.location } accessHelper={ ProjectHelper } items={ this.props.projects } onAction={ this.onAction } title="Projects" + placeholder={ + +

Welcome to HPC Cloud

+ You haven't created any projects yet
+ Add one with the above. +
+ } + /> + } />); }, }); diff --git a/src/pages/Project/View/index.js b/src/pages/Project/View/index.js index cb0d67fd..6a907956 100644 --- a/src/pages/Project/View/index.js +++ b/src/pages/Project/View/index.js @@ -1,8 +1,9 @@ import React from 'react'; import { SimulationHelper } from '../../../utils/AccessHelper'; import TableListing from '../../../panels/TableListing'; +import EmptyPlaceholder from '../../../panels/EmptyPlaceholder'; -import breadCrumbStyle from 'HPCCloudStyle/Theme.mcss'; +import theme from 'HPCCloudStyle/Theme.mcss'; import { connect } from 'react-redux'; import { dispatch } from '../../../redux'; @@ -59,14 +60,21 @@ const ProjectView = React.createClass({ breadcrumb={{ paths: ['/', `/View/Project/${this.props.params.id}`], icons: [ - breadCrumbStyle.breadCrumbRootIcon, - breadCrumbStyle.breadCrumbProjectIcon, + theme.breadCrumbRootIcon, + theme.breadCrumbProjectIcon, ] }} location={ this.props.location } accessHelper={ SimulationHelper } items={ this.props.simulations } onAction={ this.onAction } title={ `${this.props.project.name} / Simulations` } + placeholder={ + There are no simulations for this project
+ You can add some with the above. + } + /> + } />); }, }); diff --git a/src/panels/EmptyPlaceholder/index.js b/src/panels/EmptyPlaceholder/index.js new file mode 100644 index 00000000..6d9865f5 --- /dev/null +++ b/src/panels/EmptyPlaceholder/index.js @@ -0,0 +1,24 @@ +import React from 'react'; +import style from 'HPCCloudStyle/Layout.mcss'; + +// used for empty placeholders on some pages + +const classes = [ + style.verticalFlexContainer, + style.fullWidth, + style.halfHeight, + style.horizontalCenter, + style.verticalCenter, + style.textCenter, +].join(' '); + +const placeholder = (props) => ( +
+ { props.phrase } +
+); + +placeholder.displayName = 'EmptyPlaceholder'; +placeholder.propTypes = { phrase: React.PropTypes.string }; + +export default placeholder; diff --git a/src/panels/TableListing/index.js b/src/panels/TableListing/index.js index f4bc9d9d..1af2008e 100644 --- a/src/panels/TableListing/index.js +++ b/src/panels/TableListing/index.js @@ -29,6 +29,7 @@ export default React.createClass({ location: React.PropTypes.object, onAction: React.PropTypes.func, title: React.PropTypes.string, + placeholder: React.PropTypes.object, }, contextTypes: { @@ -111,6 +112,43 @@ export default React.createClass({ updateQuery(this.props.location.query.filter); const filteredList = this.props.items.filter(itemFilter); const helper = this.props.accessHelper; + let content = null; + + if (this.props.items.length) { + content = ( + + + + + + + + + + + + + { filteredList.map((item, index) => + + + + + + + + + )} + +
NameDescriptionCreatedUpdated
+ + { helper.getName(item) }{ helper.getDescription(item, true) }{ helper.getCreationDate(item, true) }{ helper.getUpdateDate(item, true) } + +
); + } else if (this.props.placeholder) { + content = this.props.placeholder; + } return (
@@ -122,36 +160,7 @@ export default React.createClass({ onAction={ this.toolbarAction } filter /> - - - - - - - - - - - - - { filteredList.map((item, index) => - - - - - - - - - )} - -
NameDescriptionCreatedUpdated
- - { helper.getName(item) }{ helper.getDescription(item, true) }{ helper.getCreationDate(item, true) }{ helper.getUpdateDate(item, true) } - -
+ { content }
); }, }); diff --git a/style/Layout.mcss b/style/Layout.mcss index 6bf2009f..b2284f30 100644 --- a/style/Layout.mcss +++ b/style/Layout.mcss @@ -54,6 +54,10 @@ width: 100%; } +.halfHeight { + height: 50vh; +} + .horizontalPadding { padding-left: 10px; padding-right: 10px; diff --git a/style/Theme.mcss b/style/Theme.mcss index 606777ce..59659ee2 100644 --- a/style/Theme.mcss +++ b/style/Theme.mcss @@ -140,6 +140,12 @@ composes: fa-pencil from 'font-awesome/css/font-awesome.css'; } +.addIcon { + composes: fa from 'font-awesome/css/font-awesome.css'; + composes: fa-fw from 'font-awesome/css/font-awesome.css'; + composes: fa-plus from 'font-awesome/css/font-awesome.css'; +} + /* Simulation icons */ .simulationEditIcon { composes: fa from 'font-awesome/css/font-awesome.css'; diff --git a/style/Toolbar.mcss b/style/Toolbar.mcss index 8ba74d41..c8bc0a19 100644 --- a/style/Toolbar.mcss +++ b/style/Toolbar.mcss @@ -33,7 +33,6 @@ align-items: center; } - .actionButton { composes: isClickable from 'HPCCloudStyle/States.mcss'; padding: 7px 17px;