diff --git a/src/app/home/index.js b/src/app/home/index.js
index b084fb35e2d..b5a9abc8c2d 100644
--- a/src/app/home/index.js
+++ b/src/app/home/index.js
@@ -151,12 +151,6 @@ var HomeView = View.extend({
'server memory size (gb)': app.instance.host.memory_bits / 1024 / 1024 / 1024
});
- const model = this._getCollection();
- // When the current collection no longer exists
- if (NamespaceStore.ns && !model) {
- NamespaceStore.ns = null;
- }
-
if (!NamespaceStore.ns) {
app.instance.collections.unselectAll();
if (app.instance.collections.length === 0) {
diff --git a/src/internal-packages/database/index.js b/src/internal-packages/database/index.js
index d981c929591..44c3bd5d3cf 100644
--- a/src/internal-packages/database/index.js
+++ b/src/internal-packages/database/index.js
@@ -1,11 +1,17 @@
const app = require('ampersand-app');
const CollectionsTable = require('./lib/components');
+const CreateCollectionCheckbox = require('./lib/components/create-collection-checkbox');
+const CreateCollectionInput = require('./lib/components/create-collection-input');
+const CreateCollectionSizeInput = require('./lib/components/create-collection-size-input');
/**
* Activate all the components in the Schema package.
*/
function activate() {
app.appRegistry.registerComponent('Database.CollectionsTable', CollectionsTable);
+ app.appRegistry.registerComponent('Database.CreateCollectionCheckbox', CreateCollectionCheckbox);
+ app.appRegistry.registerComponent('Database.CreateCollectionInput', CreateCollectionInput);
+ app.appRegistry.registerComponent('Database.CreateCollectionSizeInput', CreateCollectionSizeInput);
}
/**
@@ -13,6 +19,9 @@ function activate() {
*/
function deactivate() {
app.appRegistry.deregisterComponent('Database.CollectionsTable');
+ app.appRegistry.deregisterComponent('Database.CreateCollectionCheckbox');
+ app.appRegistry.deregisterComponent('Database.CreateCollectionInput');
+ app.appRegistry.deregisterComponent('Database.CreateCollectionSizeInput');
}
module.exports.activate = activate;
diff --git a/src/internal-packages/database/lib/actions/collections-actions.js b/src/internal-packages/database/lib/actions/collections-actions.js
index 8520ee37f8a..db458055dfd 100644
--- a/src/internal-packages/database/lib/actions/collections-actions.js
+++ b/src/internal-packages/database/lib/actions/collections-actions.js
@@ -1,12 +1,14 @@
const Reflux = require('reflux');
/**
- * The actions used by the server stats components.
+ * The actions used by the database components.
*/
const Actions = Reflux.createActions([
'sortCollections',
- 'deleteCollection',
- 'createCollection'
+ 'dropCollection',
+ 'createCollection',
+ 'openCreateCollectionDialog',
+ 'openDropCollectionDialog'
]);
module.exports = Actions;
diff --git a/src/internal-packages/database/lib/components/collections-table.jsx b/src/internal-packages/database/lib/components/collections-table.jsx
index 6ac6979d8c3..6140a85816f 100644
--- a/src/internal-packages/database/lib/components/collections-table.jsx
+++ b/src/internal-packages/database/lib/components/collections-table.jsx
@@ -1,6 +1,8 @@
const React = require('react');
const app = require('ampersand-app');
const CollectionsActions = require('../actions/collections-actions');
+const CreateCollectionDialog = require('./create-collection-dialog');
+const TextButton = require('hadron-app-registry').TextButton;
const numeral = require('numeral');
const _ = require('lodash');
@@ -22,6 +24,10 @@ class CollectionsTable extends React.Component {
// CollectionsActions.deleteCollection(collName);
}
+ onCreateCollectionButtonClicked() {
+ CollectionsActions.openCreateCollectionDialog();
+ }
+
render() {
// convert some of the values to human-readable units (MB, GB, ...)
// we do this here so that sorting is not affected in the store
@@ -45,6 +51,12 @@ class CollectionsTable extends React.Component {
return (
);
}
diff --git a/src/internal-packages/server-stats/lib/component/create-collection-checkbox.jsx b/src/internal-packages/database/lib/components/create-collection-checkbox.jsx
similarity index 94%
rename from src/internal-packages/server-stats/lib/component/create-collection-checkbox.jsx
rename to src/internal-packages/database/lib/components/create-collection-checkbox.jsx
index 1a6243e4523..4451c973b2a 100644
--- a/src/internal-packages/server-stats/lib/component/create-collection-checkbox.jsx
+++ b/src/internal-packages/database/lib/components/create-collection-checkbox.jsx
@@ -1,5 +1,8 @@
const React = require('react');
+/**
+ * A checkbox in the create collection dialog.
+ */
class CreateCollectionCheckbox extends React.Component {
/**
diff --git a/src/internal-packages/database/lib/components/create-collection-dialog.jsx b/src/internal-packages/database/lib/components/create-collection-dialog.jsx
new file mode 100644
index 00000000000..11a1dd0e520
--- /dev/null
+++ b/src/internal-packages/database/lib/components/create-collection-dialog.jsx
@@ -0,0 +1,204 @@
+const app = require('ampersand-app');
+const shell = require('electron').shell;
+const React = require('react');
+const Modal = require('react-bootstrap').Modal;
+const TextButton = require('hadron-app-registry').TextButton;
+const NamespaceStore = require('hadron-reflux-store').NamespaceStore;
+const toNS = require('mongodb-ns');
+const Actions = require('../actions/collections-actions');
+const CreateCollectionStore = require('../stores/create-collection-store');
+const CreateCollectionInput = require('./create-collection-input');
+const CreateCollectionSizeInput = require('./create-collection-size-input');
+const CreateCollectionCheckbox = require('./create-collection-checkbox');
+
+/**
+ * The help icon for capped collections url.
+ */
+const HELP_URL = 'https://docs.mongodb.com/manual/core/capped-collections/';
+
+/**
+ * The dialog to create a collection.
+ */
+class CreateCollectionDialog extends React.Component {
+
+ /**
+ * The component constructor.
+ *
+ * @param {Object} props - The properties.
+ */
+ constructor(props) {
+ super(props);
+ this.state = { open: false };
+ this.ModalStatusMessage = app.appRegistry.getComponent('App.ModalStatusMessage');
+ }
+
+ /**
+ * Subscribe to the open dialog store.
+ */
+ componentWillMount() {
+ this.unsubscribeOpen = Actions.openCreateCollectionDialog.listen(this.onOpenDialog.bind(this));
+ this.unsubscribeCreate = CreateCollectionStore.listen(this.onCollectionCreated.bind(this));
+ }
+
+ /**
+ * Unsubscribe from the store.
+ */
+ componentWillUnmount() {
+ this.unsubscribeOpen();
+ this.unsubscribeCreate();
+ }
+
+ /**
+ * When the open dialog action is fired.
+ */
+ onOpenDialog() {
+ this.setState({
+ open: true,
+ collectionName: '',
+ databaseName: toNS(NamespaceStore.ns).database,
+ capped: false,
+ maxSize: '',
+ error: false,
+ inProgress: false,
+ errorMessage: ''
+ });
+ }
+
+ /**
+ * When the cancel button is clicked.
+ */
+ onCancelButtonClicked() {
+ this.setState({ open: false });
+ }
+
+ /**
+ * Initiate the attempt to create a collection.
+ */
+ onCreateCollectionButtonClicked() {
+ this.setState({ inProgress: true, error: false, errorMessage: '' });
+ Actions.createCollection(
+ this.state.databaseName,
+ this.state.collectionName,
+ this.state.capped,
+ this.state.maxSize
+ );
+ }
+
+ /**
+ * Handle finish collection creation.
+ *
+ * @param {Error} error - The error, if any.
+ */
+ onCollectionCreated(error) {
+ if (error) {
+ this.setState({ inProgress: false, error: true, errorMessage: error.message });
+ } else {
+ this.setState({ inProgress: false, error: false, errorMessage: '', open: false });
+ }
+ }
+
+ /**
+ * Handle changing the collection name.
+ *
+ * @param {Event} evt - The change event.
+ */
+ onCollectionNameChange(evt) {
+ this.setState({ collectionName: evt.target.value });
+ }
+
+ /**
+ * Handle clicking the capped checkbox.
+ */
+ onCappedClicked() {
+ this.setState({ capped: !this.state.capped });
+ }
+
+ /**
+ * Handle clicking the help icon.
+
+ * @param {Event} evt - The event.
+ */
+ onHelpClicked(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ shell.openExternal(HELP_URL);
+ }
+
+ /**
+ * Change the max collection size.
+ *
+ * @param {Event} evt - The event.
+ */
+ onMaxSizeChange(evt) {
+ this.setState({ maxSize: evt.target.value });
+ }
+
+ /**
+ * Render the max size component when capped is selected.
+ *
+ * @returns {React.Component} The component.
+ */
+ renderMaxSize() {
+ if (this.state.capped) {
+ return (
+
+ );
+ }
+ }
+
+ /**
+ * Render the modal dialog.
+ *
+ * @returns {React.Component} The react component.
+ */
+ render() {
+ return (
+
+
+ Create Collection
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+CreateCollectionDialog.displayName = 'CreateCollectionDialog';
+
+module.exports = CreateCollectionDialog;
diff --git a/src/internal-packages/server-stats/lib/component/create-collection-input.jsx b/src/internal-packages/database/lib/components/create-collection-input.jsx
similarity index 92%
rename from src/internal-packages/server-stats/lib/component/create-collection-input.jsx
rename to src/internal-packages/database/lib/components/create-collection-input.jsx
index 06c2240400d..4d5b0fddc01 100644
--- a/src/internal-packages/server-stats/lib/component/create-collection-input.jsx
+++ b/src/internal-packages/database/lib/components/create-collection-input.jsx
@@ -1,5 +1,8 @@
const React = require('react');
+/**
+ * An input field in the create collection checkbox.
+ */
class CreateCollectionInput extends React.Component {
/**
diff --git a/src/internal-packages/server-stats/lib/component/create-collection-size-input.jsx b/src/internal-packages/database/lib/components/create-collection-size-input.jsx
similarity index 78%
rename from src/internal-packages/server-stats/lib/component/create-collection-size-input.jsx
rename to src/internal-packages/database/lib/components/create-collection-size-input.jsx
index 840767ba7c8..cb0daa1e4c5 100644
--- a/src/internal-packages/server-stats/lib/component/create-collection-size-input.jsx
+++ b/src/internal-packages/database/lib/components/create-collection-size-input.jsx
@@ -1,5 +1,8 @@
const React = require('react');
+/**
+ * A size input field in the create collection checkbox.
+ */
class CreateCollectionSizeInput extends React.Component {
/**
@@ -12,11 +15,11 @@ class CreateCollectionSizeInput extends React.Component {
-
{this.props.name}
+
{this.props.name}
);
}
diff --git a/src/internal-packages/database/lib/stores/collections-store.jsx b/src/internal-packages/database/lib/stores/collections-store.js
similarity index 66%
rename from src/internal-packages/database/lib/stores/collections-store.jsx
rename to src/internal-packages/database/lib/stores/collections-store.js
index e0ab4e05203..c610ca35068 100644
--- a/src/internal-packages/database/lib/stores/collections-store.jsx
+++ b/src/internal-packages/database/lib/stores/collections-store.js
@@ -39,9 +39,8 @@ const CollectionsStore = Reflux.createStore({
* Initialize everything that is not part of the store's state.
*/
init() {
- this.InstanceStore = app.appRegistry.getStore('App.InstanceStore');
NamespaceStore.listen(this.onNamespaceChanged.bind(this));
- // this.listenToExternalStore('App.InstanceStore', );
+ this.listenToExternalStore('App.InstanceStore', this.onNamespaceChanged.bind(this));
this.indexes = [];
},
@@ -62,38 +61,40 @@ const CollectionsStore = Reflux.createStore({
},
onNamespaceChanged() {
- const ns = toNS(NamespaceStore.ns);
- if (!ns.database) {
- this.setState({
- collections: []
- });
- return;
- }
-
- app.dataService.database(ns.database, {}, (err, res) => {
- if (err) {
+ if (NamespaceStore.ns) {
+ const ns = toNS(NamespaceStore.ns);
+ if (!ns.database) {
this.setState({
- fetchState: 'error',
- errorMessage: err
+ collections: []
});
return;
}
- debug('collections', res.collections);
- const unsorted = _.map(res.collections, (coll) => {
- return _.zipObject(COLL_COLUMNS, [
- coll.name, // Collection Name
- coll.document_count, // Num. Documents
- coll.size / coll.document_count, // Avg. Document Size
- coll.size, // Total Document Size
- coll.index_count, // Num Indexes
- coll.index_size // Total Index Size
- ]);
- });
- this.setState({
- collections: this._sort(unsorted)
+ app.dataService.database(ns.database, {}, (err, res) => {
+ if (err) {
+ this.setState({
+ fetchState: 'error',
+ errorMessage: err
+ });
+ return;
+ }
+ debug('collections', res.collections);
+ const unsorted = _.map(res.collections, (coll) => {
+ return _.zipObject(COLL_COLUMNS, [
+ coll.name, // Collection Name
+ coll.document_count, // Num. Documents
+ coll.size / coll.document_count, // Avg. Document Size
+ coll.size, // Total Document Size
+ coll.index_count, // Num Indexes
+ coll.index_size // Total Index Size
+ ]);
+ });
+
+ this.setState({
+ collections: this._sort(unsorted)
+ });
});
- });
+ }
},
sortCollections(column, order) {
@@ -104,14 +105,6 @@ const CollectionsStore = Reflux.createStore({
});
},
- // deleteCollection(dbName) {
- // // TODO remove collection on server
- // },
- //
- // createCollection(collName) {
- // // TODO create collection
- // }
-
/**
* log changes to the store as debug messages.
* @param {Object} prevState previous state.
@@ -119,7 +112,6 @@ const CollectionsStore = Reflux.createStore({
storeDidUpdate(prevState) {
debug('collections store changed from', prevState, 'to', this.state);
}
-
});
module.exports = CollectionsStore;
diff --git a/src/internal-packages/database/lib/stores/create-collection-store.js b/src/internal-packages/database/lib/stores/create-collection-store.js
new file mode 100644
index 00000000000..991e97533c8
--- /dev/null
+++ b/src/internal-packages/database/lib/stores/create-collection-store.js
@@ -0,0 +1,51 @@
+const Reflux = require('reflux');
+const app = require('ampersand-app');
+const Actions = require('../actions/collections-actions');
+
+/**
+ * The reflux store for creating collections.
+ */
+const CreateCollectionStore = Reflux.createStore({
+
+ /**
+ * Initialize the store.
+ */
+ init: function() {
+ this.refreshInstance = app.appRegistry.getAction('App.InstanceActions').refreshInstance;
+ this.listenTo(Actions.createCollection, this.createCollection);
+ },
+
+ /**
+ * Create the database.
+ *
+ * @param {String} dbName - The database name.
+ * @param {String} collection - The collection name.
+ * @param {Boolean} capped - If the collection is capped.
+ * @param {Number} size - The max size of the capped collection.
+ */
+ createCollection(dbName, collection, capped, size) {
+ const options = capped ? { capped: true, size: parseInt(size, 10) } : {};
+ try {
+ app.dataService.createCollection(`${dbName}.${collection}`, options, this.handleResult.bind(this));
+ } catch (e) {
+ this.handleResult(e, null);
+ }
+ },
+
+ /**
+ * Handle the create database result.
+ *
+ * @param {Error} error - The error.
+ * @param {Object} result - The result.
+ */
+ handleResult(error, result) {
+ if (error) {
+ this.trigger(error, result);
+ } else {
+ this.refreshInstance();
+ this.trigger(error, result);
+ }
+ }
+});
+
+module.exports = CreateCollectionStore;
diff --git a/src/internal-packages/database/styles/index.less b/src/internal-packages/database/styles/index.less
index 7a7c151ada5..f75d2aa2086 100644
--- a/src/internal-packages/database/styles/index.less
+++ b/src/internal-packages/database/styles/index.less
@@ -5,4 +5,9 @@
height: 100vh;
min-width: 100%;
overflow-x: scroll;
+
+ &-create-button {
+ margin-left: 23px;
+ margin-top: 15px;
+ }
}
diff --git a/src/internal-packages/server-stats/lib/component/create-database-dialog.jsx b/src/internal-packages/server-stats/lib/component/create-database-dialog.jsx
index efe6057ad65..2304ab0b9b3 100644
--- a/src/internal-packages/server-stats/lib/component/create-database-dialog.jsx
+++ b/src/internal-packages/server-stats/lib/component/create-database-dialog.jsx
@@ -5,9 +5,6 @@ const Modal = require('react-bootstrap').Modal;
const TextButton = require('hadron-app-registry').TextButton;
const Actions = require('../action/databases-actions');
const CreateDatabaseStore = require('../store/create-database-store');
-const CreateCollectionInput = require('./create-collection-input');
-const CreateCollectionSizeInput = require('./create-collection-size-input');
-const CreateCollectionCheckbox = require('./create-collection-checkbox');
/**
* The more information url.
@@ -33,6 +30,9 @@ class CreateDatabaseDialog extends React.Component {
super(props);
this.state = { open: false };
this.ModalStatusMessage = app.appRegistry.getComponent('App.ModalStatusMessage');
+ this.CreateCollectionInput = app.appRegistry.getComponent('Database.CreateCollectionInput');
+ this.CreateCollectionSizeInput = app.appRegistry.getComponent('Database.CreateCollectionSizeInput');
+ this.CreateCollectionCheckbox = app.appRegistry.getComponent('Database.CreateCollectionCheckbox');
}
/**
@@ -164,7 +164,7 @@ class CreateDatabaseDialog extends React.Component {
renderMaxSize() {
if (this.state.capped) {
return (
-
+
Create Database
-