New design for Create Database panel (#1213)
* New design for Create Database panel
diff --git a/app/addons/components/__tests__/accordion.test.js b/app/addons/components/__tests__/accordion.test.js
new file mode 100644
index 0000000..40eb602
--- /dev/null
+++ b/app/addons/components/__tests__/accordion.test.js
@@ -0,0 +1,48 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import { Accordion, AccordionItem } from '../components/accordion';
+import { mount } from 'enzyme';
+import React from 'react';
+import sinon from 'sinon';
+
+describe('Accordion', () => {
+
+ it('Shows and hides content after clicking on header', () => {
+ const el = mount(
+ <Accordion>
+ <AccordionItem title={'Click to open'}>
+ <p id="test_content">Have a great day</p>
+ </AccordionItem>
+ </Accordion>
+ );
+
+ expect(el.find('.faux--accordion__item-content').hasClass('in')).toBe(false);
+ el.find('.faux--accordion__item-header').simulate('click');
+ expect(el.find('.faux--accordion__item-content').hasClass('in')).toBe(true);
+ });
+
+ it('Calls onClick event', () => {
+ const spy = sinon.spy();
+ const el = mount(
+ <Accordion>
+ <AccordionItem title={'Click to open'} onClick={spy}>
+ <p id="test_content">Have a great day</p>
+ </AccordionItem>
+ </Accordion>
+ );
+
+ el.find('.faux--accordion__item-header').simulate('click');
+ sinon.assert.called(spy);
+ });
+
+});
diff --git a/app/addons/components/assets/less/accordion.less b/app/addons/components/assets/less/accordion.less
new file mode 100644
index 0000000..16a504f
--- /dev/null
+++ b/app/addons/components/assets/less/accordion.less
@@ -0,0 +1,27 @@
+.faux--accordion {
+ list-style: none;
+ margin: 0px;
+ width: 100%;
+}
+
+.faux--accordion__item {
+ background-color: transparent;
+ transition: all 0.5s linear;
+}
+
+.faux--accordion__item-header {
+ border: 0;
+ background-color: transparent;
+ color: inherit;
+ font-size: inherit;
+ padding-left: 0px;
+ span {
+ padding-left: 0.5rem;
+ }
+}
+
+.faux--accordion__item-content {
+ padding-left: 1.35rem;
+ padding-top: 0.75rem;
+ font-size: inherit;
+}
diff --git a/app/addons/components/assets/less/components.less b/app/addons/components/assets/less/components.less
index 480681e..a334648 100644
--- a/app/addons/components/assets/less/components.less
+++ b/app/addons/components/assets/less/components.less
@@ -12,6 +12,7 @@
@import "../../../../../assets/less/variables.less";
+@import "accordion.less";
@import "header-togglebutton.less";
@import "styled-select.less";
@import "docs.less";
diff --git a/app/addons/components/assets/less/jsonlink.less b/app/addons/components/assets/less/jsonlink.less
index a93f19e..304a848 100644
--- a/app/addons/components/assets/less/jsonlink.less
+++ b/app/addons/components/assets/less/jsonlink.less
@@ -16,6 +16,8 @@
padding: 16px 12px 12px 12px !important;
height: 64px;
background-color: rgba(0, 0, 0, 0);
+ text-align: center;
+ min-width: 55px;
}
.faux__jsonlink-link {
@@ -38,15 +40,6 @@
font-weight: 500;
}
-@media screen and (max-width: 1200px) {
- .faux__jsonlink-link {
- font-size: 10px;
- }
- .faux__jsonlink-link-brackets {
- font-size: 12px;
- }
-}
-
.faux__doclink {
text-align: center;
width: 55px;
@@ -69,3 +62,19 @@
text-decoration: none;
color: #666;
}
+
+@media (max-width: 1090px) {
+ #main:not(.closeMenu) {
+ .faux__jsonlink-link-label{
+ display: none;
+ }
+ }
+}
+
+@media (max-width: 1120px) {
+ #main.closeMenu {
+ .faux__jsonlink-link-label{
+ display: none;
+ }
+ }
+}
diff --git a/app/addons/components/components/accordion.js b/app/addons/components/components/accordion.js
new file mode 100644
index 0000000..48de9af
--- /dev/null
+++ b/app/addons/components/components/accordion.js
@@ -0,0 +1,74 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Collapse } from 'react-bootstrap';
+import classnames from 'classnames';
+
+export const Accordion = (props) => {
+ const { children, className, style } = props;
+ const classNames = classnames('faux--accordion', className);
+ return (
+ <ul className={classNames} style={style}>
+ {children}
+ </ul>
+ );
+};
+
+export class AccordionItem extends React.Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired
+ };
+
+ static defaultProps = {
+ onClick: () => { }
+ };
+
+ state = {
+ open: false
+ };
+
+ handleClick = (event) => {
+ const newOpen = !this.state.open;
+ this.setState({ open: newOpen });
+ this.props.onClick({ isOpen: newOpen, event });
+ };
+
+ render() {
+ const { children, title } = this.props;
+ const icon = this.state.open ? 'fonticon-down-open' : 'fonticon-right-open';
+ const contentClassNames = classnames(
+ 'faux--accordion__item-content', 'collapse',
+ {in: this.state.open}
+ );
+
+ return (
+ <li
+ className='faux--accordion__item'
+ onClick={this.handleClick}>
+ <button
+ type="button"
+ className={`faux--accordion__item-header`}
+ onClick={this.handleClick}>
+ <i className={icon}></i>
+ <span>{title}</span>
+ </button>
+ <Collapse in={this.state.open}>
+ <div className={contentClassNames}>
+ { children }
+ </div>
+ </Collapse>
+ </li>
+ );
+ }
+}
diff --git a/app/addons/components/components/apibar.js b/app/addons/components/components/apibar.js
index 971673f..83b44e8 100644
--- a/app/addons/components/components/apibar.js
+++ b/app/addons/components/components/apibar.js
@@ -22,7 +22,7 @@
<div className="faux__jsonlink">
<a data-bypass={true} className="faux__jsonlink-link" href={endpoint} target="_blank" rel="noopener noreferrer">
<span className="faux__jsonlink-link-brackets">{'{\u00a0}'}</span>
- <span>JSON</span>
+ <span className="faux__jsonlink-link-label">JSON</span>
</a>
</div>
);
diff --git a/app/addons/components/components/tray.js b/app/addons/components/components/tray.js
index d53570e..e37d18e 100644
--- a/app/addons/components/components/tray.js
+++ b/app/addons/components/components/tray.js
@@ -37,7 +37,7 @@
getChildren = (items) => {
const {style} = items[0];
- var className = "tray show-tray " + this.props.className;
+ const className = "tray show-tray " + this.props.className;
return (
<div key={'1'} id={this.props.id} style={{opacity: style.opacity, top: style.top + 'px'}} className={className}>
{this.props.children}
@@ -47,7 +47,7 @@
willEnter = () => {
return {
opacity: spring(1),
- top: spring(55)
+ top: spring(64)
};
};
diff --git a/app/addons/components/react-components.js b/app/addons/components/react-components.js
index 3b79712..d5223aa 100644
--- a/app/addons/components/react-components.js
+++ b/app/addons/components/react-components.js
@@ -10,6 +10,7 @@
// License for the specific language governing permissions and limitations under
// the License.
+import {Accordion, AccordionItem} from './components/accordion';
import {Badge, BadgeList} from './components/badge';
import {ToggleHeaderButton} from './components/toggleheaderbutton';
import {BulkActionComponent} from './components/bulkaction';
@@ -33,6 +34,8 @@
import {ThrottledReactSelectAsync} from './components/throttledreacselect';
export default {
+ Accordion,
+ AccordionItem,
BadgeList,
Badge,
BulkActionComponent,
diff --git a/app/addons/databases/assets/less/databases.less b/app/addons/databases/assets/less/databases.less
index 1ab30cc..70b23b5 100644
--- a/app/addons/databases/assets/less/databases.less
+++ b/app/addons/databases/assets/less/databases.less
@@ -19,32 +19,90 @@
}
.new-database-tray {
- padding: 16px 20px 28px;
+
&:before {
right: 250px;
}
input.input-xxlarge {
margin-bottom: 0px;
- width: 250px;
- .border-radius(5px 0 0 5px);
+ width: 100%;
}
a.btn {
- color: white;
- background-color: @linkColor;
margin-left: 0;
line-height: 1.5em;
border: 0px;
padding: 10px 10px 9px;
font-size: 14px;
- .border-radius(0 5px 5px 0);
- &:hover {
- background-color: #cbcbcb;
- color: white;
+ &.btn-cancel {
+ background-color: transparent;
+ border-color: @background;
+ border-width: 1px;
+ border-style: solid;
+ color: @buttonText;
+ &:hover {
+ background-color: @background;
+ color: @hoverHighlight;
+ }
}
}
+
+ .tray-contents {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 352px;
+ overflow-y: scroll;
+ }
+
+ .tray-header {
+ padding-right: 20px;
+ padding-left: 20px;
+ padding-top: 10px;
+ }
+ .tray-body {
+ flex: 1;
+ padding-right: 20px;
+ padding-left: 20px;
+ }
+ .tray-footer {
+ display: flex;
+ justify-content: space-between;
+ padding: 20px;
+ a.btn {
+ min-width: 140px;
+ }
+ }
+
+ .db-name-label {
+ font-weight: bold;
+ }
+
+ .partitioned-db-section {
+ flex: 1;
+ }
+ .partitioned-db-label {
+ font-weight: bold;
+ padding-top: 1rem;
+ }
+ .partitioned-db-options {
+ display: flex;
+ align-items: baseline;
+ input {
+ margin: 0px 10px 0px 0px;
+ }
+ }
+ .partitioned-db-help {
+ padding-top: 1rem;
+ font-size: 0.875rem;
+ border-bottom: 2px solid rgba(255, 255, 255, 0.1);
+ }
+}
+
+.new-database-tray--expanded {
+ height: calc(100% - 64px);
}
#database-pagination {
@@ -59,3 +117,21 @@
.database-actions > * {
margin-right: 10px;
}
+
+@media screen and (max-width: 768px) {
+ .add-new-database-btn span{
+ display: none;
+ }
+ .new-database-tray:before {
+ right: 185px;
+ }
+}
+
+@media screen and (max-width: 1120px) {
+ // Left nav menuy is closed
+ .new-database-tray {
+ .tray-contents {
+ width: 332px;
+ }
+ }
+}
diff --git a/app/addons/databases/components.js b/app/addons/databases/components.js
index a5b8cb5..3e260f0 100644
--- a/app/addons/databases/components.js
+++ b/app/addons/databases/components.js
@@ -12,9 +12,9 @@
// License for the specific language governing permissions and limitations under
// the License.
+import classnames from 'classnames';
import PropTypes from 'prop-types';
-
-import React, { Fragment } from "react";
+import React from "react";
import Components from "../components/react-components";
import ComponentsStore from "../components/stores";
import ComponentsActions from "../components/actions";
@@ -23,12 +23,12 @@
import Stores from "./stores";
import Actions from "./actions";
-import {Tooltip, OverlayTrigger} from 'react-bootstrap';
+import { Tooltip, OverlayTrigger } from 'react-bootstrap';
const databasesStore = Stores.databasesStore;
const deleteDbModalStore = ComponentsStore.deleteDbModalStore;
-const {DeleteDatabaseModal, ToggleHeaderButton, TrayContents} = Components;
+const { Accordion, AccordionItem, DeleteDatabaseModal, ToggleHeaderButton, TrayContents } = Components;
class DatabasesController extends React.Component {
@@ -92,7 +92,7 @@
state = this.getStoreState();
render() {
- const {loading, dbList} = this.state;
+ const { loading, dbList } = this.state;
return (
<DatabaseTable
@@ -117,7 +117,7 @@
createRows = (dbList) => {
return dbList.map((item, k) => {
return (
- <DatabaseRow item={item} key={k} showPartitionedColumn={this.props.showPartitionedColumn}/>
+ <DatabaseRow item={item} key={k} showPartitionedColumn={this.props.showPartitionedColumn} />
);
});
};
@@ -195,7 +195,7 @@
};
showDeleteDatabaseModal = (name) => {
- ComponentsActions.showDeleteDatabaseModal({showDeleteModal: true, dbId: name});
+ ComponentsActions.showDeleteDatabaseModal({ showDeleteModal: true, dbId: name });
};
render() {
@@ -203,7 +203,7 @@
item
} = this.props;
- const {encodedId, id, url, dataSize, docCount, docDelCount, showTombstoneWarning, failed, isPartitioned } = item;
+ const { encodedId, id, url, dataSize, docCount, docDelCount, showTombstoneWarning, failed, isPartitioned } = item;
const tombStoneWarning = showTombstoneWarning ?
(<GraveyardInfo docCount={docCount} docDelCount={docDelCount} />) : null;
@@ -249,7 +249,7 @@
}
}
-const GraveyardInfo = ({docCount, docDelCount}) => {
+const GraveyardInfo = ({ docCount, docDelCount }) => {
const graveyardTitle = `This database has just ${docCount} docs and ${docDelCount} deleted docs`;
const tooltip = <Tooltip id="graveyard-tooltip">{graveyardTitle}</Tooltip>;
@@ -267,7 +267,7 @@
this.state = this.getStoreState();
}
- getStoreState () {
+ getStoreState() {
return {
showPartitionedOption: databasesStore.isPartitionedDatabasesAvailable()
};
@@ -281,7 +281,7 @@
databasesStore.off('change', this.onChange, this);
}
- onChange () {
+ onChange() {
this.setState(this.getStoreState());
}
@@ -289,7 +289,9 @@
return (
<div className="header-right right-db-header flex-layout flex-row">
<JumpToDatabaseWidget loadOptions={Actions.fetchAllDbsWithKey} />
- <AddDatabaseWidget showPartitionedOption={this.state.showPartitionedOption}/>
+ <AddDatabaseWidget
+ showPartitionedOption={this.state.showPartitionedOption}
+ partitionedDbHelpText={this.props.partitionedDbHelpText} />
</div>
);
}
@@ -301,7 +303,8 @@
};
static propTypes = {
- showPartitionedOption: PropTypes.bool.isRequired
+ showPartitionedOption: PropTypes.bool.isRequired,
+ partitionedDbHelpText: PropTypes.string
};
constructor(props) {
@@ -309,7 +312,7 @@
this.state = {
isPromptVisible: false,
databaseName: '',
- partitionedSelected: false
+ partitionedSelected: undefined
};
this.onTrayToggle = this.onTrayToggle.bind(this);
@@ -318,32 +321,48 @@
this.onKeyUpInInput = this.onKeyUpInInput.bind(this);
this.onChange = this.onChange.bind(this);
this.onAddDatabase = this.onAddDatabase.bind(this);
- this.onTogglePartitioned = this.onTogglePartitioned.bind(this);
+ this.onSetPartitioned = this.onSetPartitioned.bind(this);
+ this.onSetNotPartitioned = this.onSetNotPartitioned.bind(this);
}
- onTrayToggle () {
- this.setState({isPromptVisible: !this.state.isPromptVisible});
+ getI18nText(key) {
+ if (this.props.i18n) {
+ return this.props.i18n[key];
+ }
+ return '';
}
- closeTray () {
- this.setState({isPromptVisible: false});
+ onTrayToggle() {
+ this.setState({ isPromptVisible: !this.state.isPromptVisible });
}
- focusInput () {
+ closeTray() {
+ this.setState({ isPromptVisible: false });
+ }
+
+ focusInput() {
this.newDbName.focus();
}
- onKeyUpInInput (e) {
+ onKeyUpInInput(e) {
if (e.which === 13) {
this.onAddDatabase();
}
}
- onChange (e) {
- this.setState({databaseName: e.target.value});
+ onChange(e) {
+ this.setState({ databaseName: e.target.value });
}
- onAddDatabase () {
+ onAddDatabase() {
+ if (this.props.showPartitionedOption && this.state.partitionedSelected === undefined) {
+ FauxtonAPI.addNotification({
+ type: 'error',
+ msg: 'Please select either Partitioned or Non-partitioned',
+ clear: true
+ });
+ return;
+ }
const partitioned = this.props.showPartitionedOption ?
this.state.partitionedSelected :
undefined;
@@ -354,31 +373,54 @@
);
}
- onTogglePartitioned() {
- this.setState({ partitionedSelected: !this.state.partitionedSelected });
+ onSetNotPartitioned() {
+ this.setState({ partitionedSelected: false });
}
- partitionedCheckobx() {
+ onSetPartitioned() {
+ this.setState({ partitionedSelected: true });
+ }
+
+ partitionedOption() {
if (!this.props.showPartitionedOption) {
return null;
}
+ const partitionedDbHelp = this.props.partitionedDbHelpText ? (
+ <Accordion className='partitioned-db-help'>
+ <AccordionItem title='What is a Partitioned Database?'>
+ <p dangerouslySetInnerHTML={{__html: this.props.partitionedDbHelpText}} />
+ </AccordionItem>
+ </Accordion>
+ ) : null;
return (
- <Fragment>
- <br/>
- <label style={{margin: '10px 10px 0px 0px'}}>
- <input
- id="js-partitioned-db"
- type="checkbox"
- checked={this.state.partitionedSelected}
- onChange={this.onTogglePartitioned}
- style={{margin: '0px 10px 0px 0px'}} />
- Partitioned
+ <div className='partitioned-db-section' >
+ <label htmlFor="partitioned-db" className='partitioned-db-label'>
+ Partitioning
</label>
- </Fragment>
+ <div className='partitioned-db-options'>
+ <input
+ id="partitioned-db"
+ type="radio"
+ checked={this.state.partitionedSelected === true}
+ onChange={this.onSetPartitioned} />
+ <label htmlFor="partitioned-db">Partitioned</label>
+ <input
+ id="non-partitioned-db"
+ type="radio"
+ checked={this.state.partitionedSelected === false}
+ onChange={this.onSetNotPartitioned} />
+ <label htmlFor="non-partitioned-db">Non-partitioned</label>
+ </div>
+ {partitionedDbHelp}
+ </div>
);
}
render() {
+ const classNames = classnames('new-database-tray', {
+ 'new-database-tray--expanded': this.props.showPartitionedOption
+ });
+
return (
<div>
<ToggleHeaderButton
@@ -388,19 +430,39 @@
title="Create Database"
fonticon="fonticon-new-database"
text="Create Database" />
- <TrayContents className="new-database-tray" contentVisible={this.state.isPromptVisible} closeTray={this.closeTray} onEnter={this.focusInput}>
- <span className="add-on">Create Database</span>
- <input
- id="js-new-database-name"
- ref={node => this.newDbName = node}
- type="text"
- value={this.state.databaseName}
- onChange={this.onChange} onKeyUp={this.onKeyUpInInput}
- className="input-xxlarge"
- placeholder="Name of database"
- />
- <a className="btn" id="js-create-database" onClick={this.onAddDatabase}>Create</a>
- { this.partitionedCheckobx() }
+ <TrayContents
+ className={classNames}
+ contentVisible={this.state.isPromptVisible}
+ closeTray={this.closeTray}
+ onEnter={this.focusInput} >
+ <div className='tray-contents'>
+ <div className='tray-header'>
+ <h3>Create Database</h3>
+ </div>
+ <div className='tray-body'>
+ <label htmlFor="js-new-database-name" className='db-name-label'>
+ Database name
+ </label>
+ <input
+ id="js-new-database-name"
+ ref={node => this.newDbName = node}
+ type="text"
+ value={this.state.databaseName}
+ onChange={this.onChange} onKeyUp={this.onKeyUpInInput}
+ className="input-xxlarge"
+ placeholder="database-name"
+ />
+ {this.partitionedOption()}
+ </div>
+ <div className='tray-footer'>
+ <a className="btn btn-cancel" id="js-cancel-create-database" onClick={this.closeTray}>
+ Cancel
+ </a>
+ <a className="btn btn-primary" id="js-create-database" onClick={this.onAddDatabase}>
+ Create
+ </a>
+ </div>
+ </div>
</TrayContents>
</div>
);
@@ -408,7 +470,7 @@
}
-const JumpToDatabaseWidget = ({loadOptions}) => {
+const JumpToDatabaseWidget = ({ loadOptions }) => {
return (
<div data-name="jump-to-db" className="faux-header__searchboxwrapper">
<div className="faux-header__searchboxcontainer">
@@ -417,7 +479,7 @@
placeholder="Database name"
loadOptions={loadOptions}
clearable={false}
- onChange={({value: databaseName}) => {
+ onChange={({ value: databaseName }) => {
Actions.jumpToDatabase(databaseName);
}} />
@@ -436,7 +498,7 @@
};
getStoreState = (props) => {
- const {store} = props;
+ const { store } = props;
return {
totalAmountOfDatabases: store.getTotalAmountOfDatabases(),
@@ -446,7 +508,7 @@
};
componentDidMount() {
- const {store} = this.props;
+ const { store } = this.props;
store.on('change', this.onChange, this);
}
@@ -456,12 +518,12 @@
if (this.props.store) {
this.props.store.off('change', this.onChange, this);
}
- const {store} = nextProps;
+ const { store } = nextProps;
store.on('change', this.onChange, this);
}
componentWillUnmount() {
- const {store} = this.props;
+ const { store } = this.props;
store.off('change', this.onChange, this);
}
@@ -482,7 +544,7 @@
}
render() {
- const {limit, page, totalAmountOfDatabases} = this.state;
+ const { limit, page, totalAmountOfDatabases } = this.state;
const start = 1 + (page - 1) * limit;
const end = Math.min(totalAmountOfDatabases, page * limit);
@@ -496,7 +558,7 @@
onClick={this.onPageLinkClick.bind(this)}
/>
</div>
- <PerPageSelector label="Databases per page" perPage={limit} perPageChange={this.onPerPageSelected.bind(this)}/>
+ <PerPageSelector label="Databases per page" perPage={limit} perPageChange={this.onPerPageSelected.bind(this)} />
<div className="current-databases">
Showing <span className="all-db-footer__range">{start}–{end}</span>
of <span className="all-db-footer__total-db-count">{totalAmountOfDatabases}</span>
diff --git a/app/addons/databases/layout.js b/app/addons/databases/layout.js
index 499248e..8fe25e0 100644
--- a/app/addons/databases/layout.js
+++ b/app/addons/databases/layout.js
@@ -10,6 +10,7 @@
// License for the specific language governing permissions and limitations under
// the License.
+import app from '../../app';
import React from 'react';
import FauxtonAPI from "../../core/api";
import {OnePane, OnePaneHeader, OnePaneContent, OnePaneFooter} from '../components/layouts';
@@ -24,7 +25,7 @@
endpoint={FauxtonAPI.urls('allDBs', 'apiurl')}
docURL={FauxtonAPI.constants.DOC_URLS.ALL_DBS}
>
- <RightDatabasesHeader />
+ <RightDatabasesHeader partitionedDbHelpText={app.i18n.en_US['create-db-partitioned-help']}/>
</OnePaneHeader>
<OnePaneContent>
<DatabasesController />
diff --git a/app/addons/databases/tests/nightwatch/createsDatabase.js b/app/addons/databases/tests/nightwatch/createsDatabase.js
index ad5803b..99bdf56 100644
--- a/app/addons/databases/tests/nightwatch/createsDatabase.js
+++ b/app/addons/databases/tests/nightwatch/createsDatabase.js
@@ -18,15 +18,20 @@
module.exports = {
before: function (client, done) {
- var nano = helpers.getNanoInstance(client.globals.test_settings.db_url);
- nano.db.destroy(newDatabaseName, function () {
+ const nano = helpers.getNanoInstance(client.globals.test_settings.db_url);
+ nano.db.destroy(newDatabaseName).then(() => {
+ done();
+ }).catch(() => {
done();
});
},
after: function (client, done) {
- var nano = helpers.getNanoInstance(client.globals.test_settings.db_url);
- nano.db.destroy(newDatabaseName, function () {
+ const nano = helpers.getNanoInstance(client.globals.test_settings.db_url);
+ nano.db.destroy(newDatabaseName).then(() => {
+ done();
+ }).catch(() => {
+ console.warn(`Could not delete ${newDatabaseName} db`);
done();
});
},
@@ -46,6 +51,7 @@
.waitForElementVisible('#js-new-database-name', waitTime, false)
.setValue('#js-new-database-name', [newDatabaseName])
.clickWhenVisible('#js-create-database', waitTime, false)
+ .waitForElementNotPresent('.new-database-tray', waitTime, false)
.checkForDatabaseCreated(newDatabaseName, waitTime)
.url(baseUrl + '/_all_dbs')
.waitForElementVisible('html', waitTime, false)
diff --git a/app/addons/documents/assets/less/query-options.less b/app/addons/documents/assets/less/query-options.less
index f2ace1a..2caa9b3 100644
--- a/app/addons/documents/assets/less/query-options.less
+++ b/app/addons/documents/assets/less/query-options.less
@@ -11,7 +11,7 @@
// the License.
#query-options-tray:before {
- right: 180px;
+ right: 225px;
}
#query-options-tray {
diff --git a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
index 9b36447..3c63c92 100644
--- a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
+++ b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
@@ -100,8 +100,8 @@
getTray () {
return (
<TrayContents closeTray={this.closeTray.bind(this)} contentVisible={this.props.contentVisible}
- className="query-options"
- id="query-options-tray">
+ className="query-options" id="query-options-tray"
+ container={this}>
<form onSubmit={this.executeQuery.bind(this)} className="js-view-query-update custom-inputs">
<MainFieldsView
diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less
index 5658e2e..93c876c 100644
--- a/assets/less/fauxton.less
+++ b/assets/less/fauxton.less
@@ -555,7 +555,7 @@
}
}
-@media (max-width: 1000px) {
+@media (max-width: 860px) {
.closeMenu {
.with-sidebar {
.faux-header__searchboxwrapper {
@@ -576,7 +576,7 @@
}
}
-@media (max-width: 1285px) {
+@media (max-width: 1015px) {
#main:not(.closeMenu) {
.with-sidebar {
.faux-header__searchboxwrapper {
@@ -626,7 +626,7 @@
margin: 2px 0 0 0;
}
#query-options-tray:before {
- right: 130px;
+ right: 180px;
}
.api-bar-tray:before {
right: 68px;
@@ -664,6 +664,9 @@
button i:before {
float: none;
}
+ #query-options-tray:before {
+ right: 180px;
+ }
.right-header button i:before {
margin: 2px 0 0 0;
}
diff --git a/assets/less/trays.less b/assets/less/trays.less
index 0d55e80..5b99034 100644
--- a/assets/less/trays.less
+++ b/assets/less/trays.less
@@ -25,7 +25,7 @@
.tray {
display: none;
position: absolute;
- right: 5px;
+ right: 0px;
top: 55px;
z-index: 11;
background-color: #333;
diff --git a/i18n.json.default.json b/i18n.json.default.json
index d104dcc..2c548b5 100644
--- a/i18n.json.default.json
+++ b/i18n.json.default.json
@@ -21,6 +21,7 @@
"auth-admin-created": "CouchDB admin created",
"auth-change-password": "Your password has been updated.",
"auth-admin-creation-failed-prefix": "Could not create admin.",
- "auth-passwords-not-matching": "Passwords do not match."
+ "auth-passwords-not-matching": "Passwords do not match.",
+ "create-db-partitioned-help": "A partitioned database requires a partition key for every document, where the document _id format is '<partition_key>:<doc_key>'. A partition is a logical grouping of documents. Partition queries are often faster than global ones."
}
}
diff --git a/test/nightwatch_tests/custom-commands/helper.js b/test/nightwatch_tests/custom-commands/helper.js
index 64f3abc..1c3c187 100644
--- a/test/nightwatch_tests/custom-commands/helper.js
+++ b/test/nightwatch_tests/custom-commands/helper.js
@@ -21,7 +21,7 @@
exports.checkForDatabaseCreated = function checkForDatabaseCreated (couchUrl, databaseName, timeout, cb) {
const timeOutId = setTimeout(() => {
- throw new Error('timeout waiting for db to appear');
+ throw new Error('Timeout ('+timeout+') waiting for db to appear');
}, timeout);
const intervalId = setInterval(() => {