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 (
);
},
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 (
);
},
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 = (
+
+
+
+ |
+ Name |
+ Description |
+ Created |
+ Updated |
+ |
+
+
+
+ { filteredList.map((item, index) =>
+
+
+
+ |
+ { 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
/>
-
-
-
- |
- Name |
- Description |
- Created |
- Updated |
- |
-
-
-
- { filteredList.map((item, index) =>
-
-
-
- |
- { 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;