diff --git a/src/internal-packages/database-ddl/lib/component/create-database-dialog.jsx b/src/internal-packages/database-ddl/lib/component/create-database-dialog.jsx index 7679f59dfdb..1cba01d5879 100644 --- a/src/internal-packages/database-ddl/lib/component/create-database-dialog.jsx +++ b/src/internal-packages/database-ddl/lib/component/create-database-dialog.jsx @@ -5,6 +5,7 @@ const Modal = require('react-bootstrap').Modal; const { TextButton } = require('hadron-react-buttons'); const Actions = require('../action'); const CreateDatabaseStore = require('../store/create-database-store'); +const { NamespaceStore } = require('hadron-reflux-store'); /** * The more information url. @@ -88,6 +89,7 @@ class CreateDatabaseDialog extends React.Component { this.state.capped, this.state.maxSize ); + NamespaceStore.ns = ''; } /** diff --git a/src/internal-packages/database-ddl/lib/component/drop-database-dialog.jsx b/src/internal-packages/database-ddl/lib/component/drop-database-dialog.jsx index 9b5688df585..549f5ea4bc1 100644 --- a/src/internal-packages/database-ddl/lib/component/drop-database-dialog.jsx +++ b/src/internal-packages/database-ddl/lib/component/drop-database-dialog.jsx @@ -1,6 +1,7 @@ const app = require('ampersand-app'); const React = require('react'); const Modal = require('react-bootstrap').Modal; +const { NamespaceStore } = require('hadron-reflux-store'); const { TextButton } = require('hadron-react-buttons'); const Actions = require('../action'); const DropDatabaseStore = require('../store/drop-database-store'); @@ -62,11 +63,13 @@ class DropDatabaseDialog extends React.Component { evt.stopPropagation(); // prevent drop database if names don't match - if (this.state.confirmName !== this.state.name) { + const databaseName = this.state.name; + if (this.state.confirmName !== databaseName) { return; } this.setState({ inProgress: true, error: false, errorMessage: '' }); - Actions.dropDatabase(this.state.name); + Actions.dropDatabase(databaseName); + NamespaceStore.ns = ''; } /** diff --git a/src/internal-packages/database/index.js b/src/internal-packages/database/index.js index bdb190c42de..b78bd81ca0d 100644 --- a/src/internal-packages/database/index.js +++ b/src/internal-packages/database/index.js @@ -1,4 +1,5 @@ const app = require('ampersand-app'); +const CollectionsAction = require('./lib/actions/collections-actions'); const CollectionsTable = require('./lib/components'); const CreateCollectionCheckbox = require('./lib/components/create-collection-checkbox'); const CreateCollectionInput = require('./lib/components/create-collection-input'); @@ -10,6 +11,7 @@ const DropCollectionDialog = require('./lib/components/drop-collection-dialog'); * Activate all the components in the Schema package. */ function activate() { + app.appRegistry.registerAction('Database.CollectionsActions', CollectionsAction); app.appRegistry.registerComponent('Database.CollectionsTable', CollectionsTable); app.appRegistry.registerComponent('Database.CreateCollectionCheckbox', CreateCollectionCheckbox); app.appRegistry.registerComponent('Database.CreateCollectionInput', CreateCollectionInput); @@ -22,6 +24,7 @@ function activate() { * Deactivate all the components in the Schema package. */ function deactivate() { + app.appRegistry.deregisterAction('Database.CollectionsActions'); app.appRegistry.deregisterComponent('Database.CollectionsTable'); app.appRegistry.deregisterComponent('Database.CreateCollectionCheckbox'); app.appRegistry.deregisterComponent('Database.CreateCollectionInput'); diff --git a/src/internal-packages/database/lib/components/create-collection-dialog.jsx b/src/internal-packages/database/lib/components/create-collection-dialog.jsx index dd93ea8f635..5554930f945 100644 --- a/src/internal-packages/database/lib/components/create-collection-dialog.jsx +++ b/src/internal-packages/database/lib/components/create-collection-dialog.jsx @@ -2,6 +2,7 @@ const app = require('ampersand-app'); const shell = require('electron').shell; const React = require('react'); const Modal = require('react-bootstrap').Modal; +const { NamespaceStore } = require('hadron-reflux-store'); const { TextButton } = require('hadron-react-buttons'); const Actions = require('../actions/collections-actions'); const CreateCollectionStore = require('../stores/create-collection-store'); @@ -80,12 +81,14 @@ class CreateCollectionDialog extends React.Component { evt.stopPropagation(); this.setState({ inProgress: true, error: false, errorMessage: '' }); + const databaseName = this.state.databaseName; Actions.createCollection( - this.state.databaseName, + databaseName, this.state.collectionName, this.state.capped, this.state.maxSize ); + NamespaceStore.ns = databaseName; } /** diff --git a/src/internal-packages/database/lib/components/drop-collection-dialog.jsx b/src/internal-packages/database/lib/components/drop-collection-dialog.jsx index 4e05301ff93..974f19142fd 100644 --- a/src/internal-packages/database/lib/components/drop-collection-dialog.jsx +++ b/src/internal-packages/database/lib/components/drop-collection-dialog.jsx @@ -1,6 +1,7 @@ const app = require('ampersand-app'); const React = require('react'); const Modal = require('react-bootstrap').Modal; +const { NamespaceStore } = require('hadron-reflux-store'); const { TextButton } = require('hadron-react-buttons'); const Actions = require('../actions/collections-actions'); const DropCollectionStore = require('../stores/drop-collection-store'); @@ -74,6 +75,7 @@ class DropCollectionDialog extends React.Component { this.setState({ inProgress: true, error: false, errorMessage: '' }); Actions.dropCollection(this.state.databaseName, this.state.collectionName); + NamespaceStore.ns = this.state.databaseName; } /** diff --git a/src/internal-packages/sidebar/lib/components/constants.js b/src/internal-packages/sidebar/lib/components/constants.js new file mode 100644 index 00000000000..9490c49571f --- /dev/null +++ b/src/internal-packages/sidebar/lib/components/constants.js @@ -0,0 +1,11 @@ +const TOOLTIP_IDS = Object.freeze({ + CREATE_COLLECTION: 'create-collection', + CREATE_DATABASE_BUTTON: 'create-database-button', + CREATE_DATABASE_ICON: 'create-database-icon', + DROP_COLLECTION: 'drop-collection', + DROP_DATABASE: 'drop-database' +}); + +module.exports = { + TOOLTIP_IDS +}; diff --git a/src/internal-packages/sidebar/lib/components/sidebar-collection.jsx b/src/internal-packages/sidebar/lib/components/sidebar-collection.jsx index b4a62a00689..1d593262790 100644 --- a/src/internal-packages/sidebar/lib/components/sidebar-collection.jsx +++ b/src/internal-packages/sidebar/lib/components/sidebar-collection.jsx @@ -1,9 +1,12 @@ const app = require('ampersand-app'); const React = require('react'); +const ReactTooltip = require('react-tooltip'); const ipc = require('hadron-ipc'); const { NamespaceStore } = require('hadron-reflux-store'); +const { TOOLTIP_IDS } = require('./constants'); + class SidebarCollection extends React.Component { constructor() { super(); @@ -11,6 +14,7 @@ class SidebarCollection extends React.Component { active: false }; this.handleClick = this.handleClick.bind(this); + this.CollectionsActions = app.appRegistry.getAction('Database.CollectionsActions'); this.CollectionStore = app.appRegistry.getStore('App.CollectionStore'); } @@ -28,6 +32,14 @@ class SidebarCollection extends React.Component { } } + handleDropCollectionClick(isWritable) { + if (isWritable) { + const databaseName = this.props.database; + const collectionName = this.getCollectionName(); + this.CollectionsActions.openDropCollectionDialog(databaseName, collectionName); + } + } + renderReadonly() { if (this.props.readonly) { return ( @@ -38,15 +50,35 @@ class SidebarCollection extends React.Component { render() { const collectionName = this.getCollectionName(); - let className = 'compass-sidebar-title compass-sidebar-title-is-actionable'; + const isWritable = app.dataService.isWritable(); + const tooltipText = isWritable ? + 'Drop collection' : + 'Drop collection is not available on a secondary node'; // TODO: Arbiter/recovering/etc + const tooltipOptions = { + 'data-for': TOOLTIP_IDS.DROP_COLLECTION, + 'data-effect': 'solid', + 'data-offset': "{'bottom': 18, 'left': 3}", + 'data-tip': tooltipText + }; + let titleClassName = 'compass-sidebar-title compass-sidebar-title-is-actionable'; if (this.props.activeNamespace === this.props._id) { - className += ' compass-sidebar-title-is-active'; + titleClassName += ' compass-sidebar-title-is-active'; + } + let dropClassName = 'compass-sidebar-icon compass-sidebar-icon-drop-collection fa fa-trash-o'; + if (!isWritable) { + dropClassName += ' compass-sidebar-icon-is-disabled'; } return (
+ +
{collectionName}  diff --git a/src/internal-packages/sidebar/lib/components/sidebar-database.jsx b/src/internal-packages/sidebar/lib/components/sidebar-database.jsx index e05cb1419ae..3f5c5ae1a8e 100644 --- a/src/internal-packages/sidebar/lib/components/sidebar-database.jsx +++ b/src/internal-packages/sidebar/lib/components/sidebar-database.jsx @@ -1,14 +1,19 @@ const app = require('ampersand-app'); const ipc = require('hadron-ipc'); const React = require('react'); -const SidebarCollection = require('./sidebar-collection'); +const ReactTooltip = require('react-tooltip'); const { NamespaceStore } = require('hadron-reflux-store'); const toNS = require('mongodb-ns'); +const { TOOLTIP_IDS } = require('./constants'); +const SidebarCollection = require('./sidebar-collection'); + class SidebarDatabase extends React.Component { constructor(props) { super(props); this.state = { expanded: props.expanded }; + this.CollectionsActions = app.appRegistry.getAction('Database.CollectionsActions'); + this.DatabaseDDLActions = app.appRegistry.getAction('DatabaseDDL.Actions'); this.CollectionStore = app.appRegistry.getStore('App.CollectionStore'); } @@ -54,16 +59,68 @@ class SidebarDatabase extends React.Component { this.setState({ expanded: !this.state.expanded }); } + handleCreateCollectionClick(isWritable) { + if (isWritable) { + const databaseName = this.props._id; + this.CollectionsActions.openCreateCollectionDialog(databaseName); + } + } + + handleDropDBClick(isWritable) { + if (isWritable) { + const databaseName = this.props._id; + this.DatabaseDDLActions.openDropDatabaseDialog(databaseName); + } + } + render() { - let className = 'compass-sidebar-item-header compass-sidebar-item-header-is-expandable compass-sidebar-item-header-is-actionable'; + const isWritable = app.dataService.isWritable(); + const createTooltipText = isWritable ? + 'Create collection' : + 'Create collection is not available on a secondary node'; // TODO: Arbiter/recovering/etc + const createTooltipOptions = { + 'data-for': TOOLTIP_IDS.CREATE_COLLECTION, + 'data-effect': 'solid', + 'data-offset': "{'bottom': 18, 'left': 3}", + 'data-tip': createTooltipText + }; + const dropTooltipText = isWritable ? + 'Drop database' : + 'Drop database is not available on a secondary node'; // TODO: Arbiter/recovering/etc + const dropTooltipOptions = { + 'data-for': TOOLTIP_IDS.DROP_DATABASE, + 'data-effect': 'solid', + 'data-offset': "{'bottom': 18, 'left': 3}", + 'data-tip': dropTooltipText + }; + let headerClassName = 'compass-sidebar-item-header compass-sidebar-item-header-is-expandable compass-sidebar-item-header-is-actionable'; if (this.props.activeNamespace === this.props._id) { - className += ' compass-sidebar-item-header-is-active'; + headerClassName += ' compass-sidebar-item-header-is-active'; + } + let createClassName = 'compass-sidebar-icon compass-sidebar-icon-create-collection fa fa-plus-circle'; + if (!isWritable) { + createClassName += ' compass-sidebar-icon-is-disabled'; + } + let dropClassName = 'compass-sidebar-icon compass-sidebar-icon-drop-database fa fa-trash-o'; + if (!isWritable) { + dropClassName += ' compass-sidebar-icon-is-disabled'; } return (
-
- - +
+ + + + +
-
- +
+ + +
diff --git a/src/internal-packages/sidebar/lib/components/sidebar.jsx b/src/internal-packages/sidebar/lib/components/sidebar.jsx index c60feb979a2..ec8abad5738 100644 --- a/src/internal-packages/sidebar/lib/components/sidebar.jsx +++ b/src/internal-packages/sidebar/lib/components/sidebar.jsx @@ -1,11 +1,10 @@ const React = require('react'); - +const ReactTooltip = require('react-tooltip'); const app = require('ampersand-app'); -const StoreConnector = app.appRegistry.getComponent('App.StoreConnector'); -const InstanceStore = app.appRegistry.getStore('App.InstanceStore'); const SidebarActions = require('../actions'); const SidebarDatabase = require('./sidebar-database'); const SidebarInstanceProperties = require('./sidebar-instance-properties'); +const { TOOLTIP_IDS } = require('./constants'); // const debug = require('debug')('mongodb-compass:sidebar:sidebar'); @@ -13,6 +12,9 @@ const SidebarInstanceProperties = require('./sidebar-instance-properties'); class Sidebar extends React.Component { constructor(props) { super(props); + this.DatabaseDDLActions = app.appRegistry.getAction('DatabaseDDL.Actions'); + this.InstanceStore = app.appRegistry.getStore('App.InstanceStore'); + this.StoreConnector = app.appRegistry.getComponent('App.StoreConnector'); this.state = { collapsed: false }; } @@ -44,6 +46,41 @@ class Sidebar extends React.Component { SidebarActions.filterDatabases(re); } + handleCreateDatabaseClick(isWritable) { + if (isWritable) { + this.DatabaseDDLActions.openCreateDatabaseDialog(); + } + } + + renderCreateDatabaseButton() { + const isWritable = app.dataService.isWritable(); + const tooltipText = 'Not available on a secondary node'; // TODO: Arbiter/recovering/etc + // Only show this tooltip on a secondary + const tooltipOptions = isWritable ? {} : { + 'data-for': TOOLTIP_IDS.CREATE_DATABASE_BUTTON, + 'data-effect': 'solid', + 'data-place': 'top', + 'data-tip': tooltipText + }; + let className = 'compass-sidebar-button-create-database'; + if (!isWritable) { + className += ' compass-sidebar-button-is-disabled'; + } + return ( + + ); + } + render() { return (
@@ -53,12 +90,12 @@ class Sidebar extends React.Component { >
- + - +
@@ -77,6 +114,7 @@ class Sidebar extends React.Component { ); }) } + {this.renderCreateDatabaseButton()}
); diff --git a/src/internal-packages/sidebar/styles/index.less b/src/internal-packages/sidebar/styles/index.less index 45890582210..d3b0a546aaf 100644 --- a/src/internal-packages/sidebar/styles/index.less +++ b/src/internal-packages/sidebar/styles/index.less @@ -1,6 +1,10 @@ +@compass-sidebar-base-background-color: #4c5259; +@compass-sidebar-active-background-color: #6D7984; +@compass-sidebar-active-hover-background-color: #7D8994; + .compass-sidebar { margin: 0; - background: #4c5259; + background: @compass-sidebar-base-background-color; color: #bfbfbe; flex-grow: 0; flex-shrink: 0; @@ -61,7 +65,7 @@ &-is-active, &-is-active:hover { - background-color: #6D7984; + background-color: @compass-sidebar-active-background-color; } } @@ -99,7 +103,6 @@ background-color: #6D7984; //there's got to be a better way to handle styles on the child when parent -is-active - .compass-sidebar-database-icon, .compass-sidebar-expand-icon { color: #fff; } @@ -114,7 +117,7 @@ &-expand-icon { position: absolute; top: 8px; - right: 9px; + left: 9px; transition: all 180ms ease-out; color: #9DA4AA; } @@ -123,14 +126,73 @@ color: #fff; } - &-database-icon { + &-button { + &-create-database { + background-color: @compass-sidebar-active-background-color; + border-radius: 12px; + border: grey; + color: #fff; + margin: 4px 10px 16px 10px; + padding: 5px; + width: 230px; + + .fa-plus { + width: 20px; + } + .plus-button { + font-size: 11px; + font-weight: bold; + text-transform: uppercase; + } + } + &-create-database:hover { + background-color: @compass-sidebar-active-hover-background-color; + } + } + + &-icon { + color: @compass-sidebar-base-background-color; + font-size: 17px; position: absolute; - top: 6px; - left: 10px; + top: 0; transition: all 180ms ease-out; - color: #797F84; - font-family: "MMS Icons"; - font-style: normal; + + &-create-database { + // Quick hack so the icon doesn't end up on the right of the entire page + // with the new collapsible sidebar. Designers feel welcome to improve :) + left: 222px; + top: 12px; + } + + &-create-collection { + right: 22px; + } + + &-create-database, + &-create-collection { + padding: 7px 9px 8px 3px; + } + + // database and collection sidebar rows have slightly different heights + &-drop-database { + padding: 7px 9px 8px 3px; + } + &-drop-collection { + padding: 6px 9px 6px 3px; + } + + &-drop-database, + &-drop-collection { + right: 0; + } + + &-is-active:hover { + background: @compass-sidebar-active-background-color; + } + + &:hover { + color: #fff; + } } &-item-content { @@ -241,12 +303,20 @@ &-is-active, &-is-active:hover { - background-color: #6D7984; + background-color: @compass-sidebar-active-background-color; //there's got to be a better way to handle styles on the child when parent -is-active .compass-sidebar-instance-version { color: #fff; } + + .compass-sidebar-icon-create-database { + color: @compass-sidebar-active-background-color; + + &:hover { + color: #fff; + } + } } } @@ -296,7 +366,9 @@ .compass-sidebar-content, .compass-sidebar-property-column, .compass-sidebar-instance-hostname, - .compass-sidebar-instance-version { + .compass-sidebar-instance-version, + .compass-sidebar-icon-create-database, + .compass-sidebar-button-create-database { display: none; } .compass-sidebar-instance { diff --git a/test/enzyme/sidebar-collection.test.js b/test/enzyme/sidebar-collection.test.js new file mode 100644 index 00000000000..d3fd801c203 --- /dev/null +++ b/test/enzyme/sidebar-collection.test.js @@ -0,0 +1,86 @@ +// /* eslint no-unused-vars: 0, no-unused-expressions: 0 */ +const app = require('ampersand-app'); +const chai = require('chai'); +const chaiEnzyme = require('chai-enzyme'); +const expect = chai.expect; +const React = require('react'); +const sinon = require('sinon'); +const AppRegistry = require('hadron-app-registry'); +const { shallow } = require('enzyme'); +const SidebarCollection = require('../../src/internal-packages/sidebar/lib/components/sidebar-collection'); + +chai.use(chaiEnzyme()); + +const appDataService = app.dataService; +const appRegistry = app.appRegistry; + +describe('', () => { + beforeEach(function() { + app.appRegistry = new AppRegistry(); + this.DatabaseDDLActionSpy = sinon.spy(); + app.appRegistry.registerAction( + 'Database.CollectionsActions', + {openDropCollectionDialog: this.DatabaseDDLActionSpy} + ); + app.dataService = { + isWritable: () => { + return true; + } + }; + }); + afterEach(() => { + app.dataService = appDataService; + app.appRegistry = appRegistry; + }); + + context('when dataService is not writable', function() { + beforeEach(function() { + app.dataService = { + isWritable: () => { + return false; + } + }; + this.component = shallow( + ); + }); + it('drop collection contains a disabled BEM modifer class', function() { + const element = this.component.find('.compass-sidebar-icon-drop-collection'); + expect(element.hasClass('compass-sidebar-icon-is-disabled')).to.be.true; + }); + it('warns the drop collection icon does not work on secondaries', function() { + const expected = 'Drop collection is not available on a secondary node'; + const element = this.component.find('.compass-sidebar-icon-drop-collection'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('the drop collection icon triggers no action', function() { + const element = this.component.find('.compass-sidebar-icon-drop-collection'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.called).to.be.false; + }); + }); + + context('when dataService is writable', () => { + beforeEach(function() { + this.component = shallow( + ); + }); + it('renders a drop collection icon with tooltip', function() { + const expected = 'Drop collection'; + const element = this.component.find('.compass-sidebar-icon-drop-collection'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('clicking the drop collection icon triggers an action', function() { + const element = this.component.find('.compass-sidebar-icon-drop-collection'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.calledOnce).to.be.true; + }); + }); +}); diff --git a/test/enzyme/sidebar-database.test.js b/test/enzyme/sidebar-database.test.js new file mode 100644 index 00000000000..d96cc1759e4 --- /dev/null +++ b/test/enzyme/sidebar-database.test.js @@ -0,0 +1,115 @@ +// /* eslint no-unused-vars: 0, no-unused-expressions: 0 */ +const app = require('ampersand-app'); +const chai = require('chai'); +const chaiEnzyme = require('chai-enzyme'); +const expect = chai.expect; +const React = require('react'); +const sinon = require('sinon'); +const AppRegistry = require('hadron-app-registry'); +const { shallow } = require('enzyme'); +const SidebarDatabase = require('../../src/internal-packages/sidebar/lib/components/sidebar-database'); + +chai.use(chaiEnzyme()); + +const appDataService = app.dataService; +const appRegistry = app.appRegistry; + +describe('', () => { + beforeEach(function() { + app.appRegistry = new AppRegistry(); + this.DatabaseDDLActionSpyCreate = sinon.spy(); + this.DatabaseDDLActionSpyDrop = sinon.spy(); + app.appRegistry.registerAction( + 'Database.CollectionsActions', + {openCreateCollectionDialog: this.DatabaseDDLActionSpyCreate} + ); + app.appRegistry.registerAction( + 'DatabaseDDL.Actions', + {openDropDatabaseDialog: this.DatabaseDDLActionSpyDrop} + ); + app.dataService = { + isWritable: () => { + return true; + } + }; + }); + afterEach(() => { + app.dataService = appDataService; + app.appRegistry = appRegistry; + }); + + context('when dataService is not writable', function() { + beforeEach(function() { + app.dataService = { + isWritable: () => { + return false; + } + }; + this.component = shallow( + ); + }); + it('create collection contains a disabled BEM modifer class', function() { + const element = this.component.find('.compass-sidebar-icon-create-collection'); + expect(element.hasClass('compass-sidebar-icon-is-disabled')).to.be.true; + }); + it('warns the create collection icon does not work on secondaries', function() { + const expected = 'Create collection is not available on a secondary node'; + const element = this.component.find('.compass-sidebar-icon-create-collection'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('the create collection icon triggers no action', function() { + const element = this.component.find('.compass-sidebar-icon-create-collection'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpyCreate.called).to.be.false; + }); + + it('drop database contains a disabled BEM modifer class', function() { + const element = this.component.find('.compass-sidebar-icon-drop-database'); + expect(element.hasClass('compass-sidebar-icon-is-disabled')).to.be.true; + }); + it('warns the drop database icon does not work on secondaries', function() { + const expected = 'Drop database is not available on a secondary node'; + const element = this.component.find('.compass-sidebar-icon-drop-database'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('the drop database icon triggers no action', function() { + const element = this.component.find('.compass-sidebar-icon-drop-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpyDrop.called).to.be.false; + }); + }); + + context('when dataService is writable', () => { + beforeEach(function() { + this.component = shallow( + ); + }); + it('renders a create collection icon with tooltip', function() { + const expected = 'Create collection'; + const element = this.component.find('.compass-sidebar-icon-create-collection'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('clicking the create collection icon triggers an action', function() { + const element = this.component.find('.compass-sidebar-icon-create-collection'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpyCreate.calledOnce).to.be.true; + }); + + it('renders a drop database icon with tooltip', function() { + const expected = 'Drop database'; + const element = this.component.find('.compass-sidebar-icon-drop-database'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('clicking the drop database icon triggers an action', function() { + const element = this.component.find('.compass-sidebar-icon-drop-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpyDrop.calledOnce).to.be.true; + }); + }); +}); diff --git a/test/enzyme/sidebar-instance-properties.test.js b/test/enzyme/sidebar-instance-properties.test.js new file mode 100644 index 00000000000..59f41143a3f --- /dev/null +++ b/test/enzyme/sidebar-instance-properties.test.js @@ -0,0 +1,164 @@ +/* eslint no-unused-vars: 0, no-unused-expressions: 0 */ +const app = require('ampersand-app'); +const chai = require('chai'); +const chaiEnzyme = require('chai-enzyme'); +const expect = chai.expect; +const React = require('react'); +const sinon = require('sinon'); +const AppRegistry = require('hadron-app-registry'); +const { shallow } = require('enzyme'); +const SidebarInstanceProperties = require('../../src/internal-packages/sidebar/lib/components/sidebar-instance-properties'); + +chai.use(chaiEnzyme()); + +const appRegistry = app.appRegistry; +const dataService = app.dataService; + +describe('', () => { + beforeEach(function() { + app.appRegistry = new AppRegistry(); + this.DatabaseDDLActionSpy = sinon.spy(); + app.appRegistry.registerAction( + 'DatabaseDDL.Actions', + {openCreateDatabaseDialog: this.DatabaseDDLActionSpy} + ); + app.dataService = { + isWritable: () => { + return true; + } + }; + }); + afterEach(() => { + app.dataService = dataService; + app.appRegistry = appRegistry; + }); + + context('when no SSH Tunnel and dataService is not writable', function() { + beforeEach(function() { + const connection = { + hostname: 'ip-1-2-3-4-mongod.com', + port: 27000, + ssh_tunnel: 'NONE' + }; + const instance = { + build: { + enterprise_module: true, + version: '3.4.0-rc3' + }, + collections: [], + databases: [] + }; + app.dataService = { + isWritable: () => { + return false; + } + }; + this.component = shallow( + ); + }); + it('create database icon contains a disabled BEM modifer class', function() { + const element = this.component.find('.compass-sidebar-icon-create-database'); + expect(element.hasClass('compass-sidebar-icon-is-disabled')).to.be.true; + }); + it('warns the create database icon does not work on secondaries', function() { + const expected = 'Create database is not available on a secondary node'; + const element = this.component.find('.compass-sidebar-icon-create-database'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('the create database icon triggers no action', function() { + const element = this.component.find('.compass-sidebar-icon-create-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.called).to.be.false; + }); + }); + + context('when rendering with no SSH Tunnel', () => { + beforeEach(function() { + const connection = { + hostname: 'ip-1-2-3-4-mongod.com', + port: 27000, + ssh_tunnel: 'NONE' + }; + const instance = { + build: { + enterprise_module: true, + version: '3.4.0-rc3' + }, + collections: [], + databases: [] + }; + this.component = shallow( + ); + }); + context('when dataService is writable', function() { + it('renders a create database icon with tooltip', function() { + const expected = 'Create database'; + const element = this.component.find('.compass-sidebar-icon-create-database'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('clicking the create database icon triggers an action', function() { + const element = this.component.find('.compass-sidebar-icon-create-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.calledOnce).to.be.true; + }); + }); + + it('renders the endpoint host name and port as text', function() { + const element = this.component.find('.compass-sidebar-instance-hostname'); + expect(element.text()).to.be.equal('ip-1-2-3-4-mongod.com:27000'); + }); + it('does not render any ssh-tunnel section', function() { + const element = this.component.find('.compass-sidebar-instance-ssh-tunnel'); + expect(element).to.not.exist; + }); + it('renders instance build version', function() { + const element = this.component.find('.compass-sidebar-instance-version'); + expect(element.text()).to.be.equal('Enterprise version 3.4.0-rc3'); + }); + }); + + context('when rendering with an SSH Tunnel', () => { + beforeEach(function() { + const connection = { + hostname: 'ip-1-2-3-4-secret-mongod.com', + port: 27017, + ssh_tunnel: 'IDENTITY_FILE', + ssh_tunnel_options: { + host: 'my-jump-box.com', + port: '2222' + } + }; + const instance = { + build: {version: '3.2.10'}, + collections: [], + databases: [] + }; + this.component = shallow( + ); + }); + it('renders the endpoint host name and port as text', function() { + const element = this.component.find('.compass-sidebar-instance-hostname'); + expect(element.text()).to.be.equal('ip-1-2-3-4-secret-mongod.com:27017'); + }); + it('renders the SSH tunnel host name and port text', function() { + const element = this.component.find('.compass-sidebar-instance-ssh-tunnel'); + expect(element.text()).to.be.equal('via SSH tunnel my-jump-box.com:2222'); + }); + it('renders instance build version', function() { + const element = this.component.find('.compass-sidebar-instance-version'); + expect(element.text()).to.be.equal('Community version 3.2.10'); + }); + }); +}); diff --git a/test/enzyme/sidebar-instance.test.js b/test/enzyme/sidebar-instance.test.js deleted file mode 100644 index 99c841f24ea..00000000000 --- a/test/enzyme/sidebar-instance.test.js +++ /dev/null @@ -1,82 +0,0 @@ -/* eslint no-unused-vars: 0, no-unused-expressions: 0 */ -const chai = require('chai'); -const chaiEnzyme = require('chai-enzyme'); -const expect = chai.expect; -const React = require('react'); - -const shallow = require('enzyme').shallow; -const SidebarInstanceProperties = require('../../src/internal-packages/sidebar/lib/components/sidebar-instance-properties'); - -chai.use(chaiEnzyme()); - -describe('', () => { - context('when rendering with no SSH Tunnel', () => { - let connection = { - hostname: 'ip-1-2-3-4-mongod.com', - port: 27000, - ssh_tunnel: 'NONE' - }; - let instance = { - build: { - enterprise_module: true, - version: '3.4.0-rc3' - }, - collections: [], - databases: [] - }; - const component = shallow( - ); - - it('renders the endpoint host name and port as text', () => { - const element = component.find('.compass-sidebar-instance-hostname'); - expect(element.text()).to.be.equal('ip-1-2-3-4-mongod.com:27000'); - }); - it('does not render any ssh-tunnel section', () => { - const element = component.find('.compass-sidebar-instance-ssh-tunnel'); - expect(element).to.not.exist; - }); - it('renders instance build version', () => { - const element = component.find('.compass-sidebar-instance-version'); - expect(element.text()).to.be.equal('Enterprise version 3.4.0-rc3'); - }); - }); - context('when rendering with an SSH Tunnel', () => { - let connection = { - hostname: 'ip-1-2-3-4-secret-mongod.com', - port: 27017, - ssh_tunnel: 'IDENTITY_FILE', - ssh_tunnel_options: { - host: 'my-jump-box.com', - port: '2222' - } - }; - let instance = { - build: {version: '3.2.10'}, - collections: [], - databases: [] - }; - const component = shallow( - ); - - it('renders the endpoint host name and port as text', () => { - const element = component.find('.compass-sidebar-instance-hostname'); - expect(element.text()).to.be.equal('ip-1-2-3-4-secret-mongod.com:27017'); - }); - it('renders the SSH tunnel host name and port text', () => { - const element = component.find('.compass-sidebar-instance-ssh-tunnel'); - expect(element.text()).to.be.equal('via SSH tunnel my-jump-box.com:2222'); - }); - it('renders instance build version', () => { - const element = component.find('.compass-sidebar-instance-version'); - expect(element.text()).to.be.equal('Community version 3.2.10'); - }); - }); -}); diff --git a/test/enzyme/sidebar.test.js b/test/enzyme/sidebar.test.js new file mode 100644 index 00000000000..b65f3d754e2 --- /dev/null +++ b/test/enzyme/sidebar.test.js @@ -0,0 +1,87 @@ +// /* eslint no-unused-vars: 0, no-unused-expressions: 0 */ +const app = require('ampersand-app'); +const chai = require('chai'); +const chaiEnzyme = require('chai-enzyme'); +const expect = chai.expect; +const React = require('react'); +const sinon = require('sinon'); +const AppRegistry = require('hadron-app-registry'); +const { shallow } = require('enzyme'); +const Sidebar = require('../../src/internal-packages/sidebar/lib/components/sidebar'); +const InstanceStore = require('../../src/internal-packages/app/lib/stores/instance-store'); +const StoreConnector = require('../../src/internal-packages/app/lib/components/store-connector'); + +chai.use(chaiEnzyme()); + +const appDataService = app.dataService; +const appRegistry = app.appRegistry; + +describe('', () => { + beforeEach(function() { + app.appRegistry = new AppRegistry(); + this.DatabaseDDLActionSpy = sinon.spy(); + app.appRegistry.registerAction( + 'DatabaseDDL.Actions', + {openCreateDatabaseDialog: this.DatabaseDDLActionSpy} + ); + app.appRegistry.registerComponent('App.StoreConnector', StoreConnector); + app.appRegistry.registerStore('App.InstanceStore', InstanceStore); + app.dataService = { + isWritable: () => { + return true; + } + }; + }); + afterEach(() => { + app.dataService = appDataService; + app.appRegistry = appRegistry; + }); + + context('when dataService is not writable', function() { + beforeEach(function() { + app.dataService = { + isWritable: () => { + return false; + } + }; + this.component = shallow( + ); + }); + it('create database button contains a disabled BEM modifer class', function() { + const element = this.component.find('.compass-sidebar-button-create-database'); + expect(element.hasClass('compass-sidebar-button-is-disabled')).to.be.true; + }); + it('warns the create database button is not available on secondaries', function() { + const expected = 'Not available on a secondary node'; + const element = this.component.find('.compass-sidebar-button-create-database'); + expect(element.prop('data-tip')).to.be.equal(expected); + }); + it('the create database button triggers no action', function() { + const element = this.component.find('.compass-sidebar-button-create-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.called).to.be.false; + }); + }); + + context('when dataService is writable', () => { + beforeEach(function() { + this.component = shallow( + ); + }); + it('renders a create database button with no tooltip', function() { + const element = this.component.find('.compass-sidebar-button-create-database'); + expect(element.prop('data-tip')).to.be.undefined; + }); + it('clicking the create database button triggers an action', function() { + const element = this.component.find('.compass-sidebar-button-create-database'); + element.simulate('click'); + expect(this.DatabaseDDLActionSpy.calledOnce).to.be.true; + }); + }); +});