diff --git a/app/components/ChangelogModal.js b/app/components/ChangelogModal.js
index 524990a84e..fb83d24405 100644
--- a/app/components/ChangelogModal.js
+++ b/app/components/ChangelogModal.js
@@ -45,7 +45,7 @@ class ChangelogModal extends ModalComponent {
if (!changelog) {
html = [
-
+
];
@@ -55,19 +55,19 @@ class ChangelogModal extends ModalComponent {
changelog.map(change => {
html = [
...html,
-
v{change.version} Changes
+
v{change.version} Changes
];
if (change.summary) {
if (!Array.isArray(change.summary)) {
html = [
...html,
-
{change.summary}
+
{change.summary}
]
} else {
html = [
...html,
-
{change.summary[0]}
,
- ...change.summary.slice(1).map(text =>
{text}
)
+
{change.summary[0]}
,
+ ...change.summary.slice(1).map((text, i) =>
{text}
)
]
}
}
@@ -75,30 +75,36 @@ class ChangelogModal extends ModalComponent {
if (change.major && change.major.length) {
html = [
...html,
-
Noteworthy
,
-
{change.major.map(text => - {text}
)}
+
Noteworthy
,
+
+ {change.major.map((text, i) => - {text}
)}
+
];
}
if (change.fixes && change.fixes.length) {
html = [
...html,
-
Fixes
,
-
{change.fixes.map(text => - {text}
)}
+
Fixes
,
+
+ {change.fixes.map(text => - {text}
)}
+
];
}
if (change.minor && change.minor.length) {
html = [
...html,
-
Minor Changes
,
-
{change.minor.map(text => - {text}
)}
+
Minor Changes
,
+
+ {change.minor.map((text, i) => - {text}
)}
+
];
}
html = [
...html,
-
+
]
});
}
diff --git a/app/components/RequestSwitcherModal.js b/app/components/RequestSwitcherModal.js
index 766aa036a7..cc1a47b35c 100644
--- a/app/components/RequestSwitcherModal.js
+++ b/app/components/RequestSwitcherModal.js
@@ -1,26 +1,214 @@
-import React from 'react';
+import React, {PropTypes} from 'react';
+import ReactDOM from 'react-dom';
+import classnames from 'classnames';
import Modal from './base/Modal';
-import ModalBody from './base/ModalBody';
import ModalHeader from './base/ModalHeader';
-import ModalFooter from './base/ModalFooter';
+import ModalBody from './base/ModalBody';
+import MethodTag from './MethodTag';
import ModalComponent from './lib/ModalComponent';
+import * as db from '../database';
+
class RequestSwitcherModal extends ModalComponent {
- render() {
+ constructor (props) {
+ super(props);
+ this.state = {
+ searchString: '',
+ matchedRequests: [],
+ requestGroups: [],
+ activeIndex: -1
+ }
+ }
+
+ _setActiveIndex (activeIndex) {
+ if (activeIndex < 0) {
+ activeIndex = this.state.matchedRequests.length - 1;
+ } else if (activeIndex >= this.state.matchedRequests.length) {
+ activeIndex = 0;
+ }
+
+ this.setState({activeIndex});
+ }
+
+ _activateCurrentIndex () {
+ if (this.state.matchedRequests.length) {
+ // Activate the request if there is one
+ this._activateRequest(this.state.matchedRequests[this.state.activeIndex]);
+ } else {
+ // Create the request if nothing matched
+ const name = this.state.searchString;
+ const parentId = this.props.activeRequest.parentId;
+
+ db.requestCreate({name, parentId}).then(request => {
+ this._activateRequest(request);
+ });
+ }
+ }
+
+ _activateRequest (request) {
+ if (!request) {
+ return;
+ }
+
+ this.props.activateRequest(request);
+ this.hide();
+ }
+
+ _handleChange (searchString) {
+ Promise.all([
+ db.requestAll(),
+ db.requestGroupAll()
+ ]).then(([
+ requests,
+ requestGroups
+ ]) => {
+ const {activeRequest} = this.props;
+ const activeRequestGroup = requestGroups.find(rg => rg._id === activeRequest.parentId);
+
+ const matchedRequests = requests.sort(
+ (a, b) => {
+ const rgA = requestGroups.find(rg => rg._id === a.parentId);
+ const rgB = requestGroups.find(rg => rg._id === b.parentId);
+
+ if (rgA === activeRequestGroup && rgB !== activeRequestGroup) {
+ return -1;
+ } else if (rgB === activeRequestGroup && rgA !== activeRequestGroup) {
+ return 1;
+ } else {
+ // TODO: Sort by quality of match (eg. start of string vs mid string, etc)
+ return (rgA || {}).name > (rgB || {}).name ? 1 : -1;
+ }
+ }
+ ).filter(r => {
+ if (!searchString) {
+ return true;
+ } else {
+ return r.name.toLowerCase().indexOf(searchString.toLowerCase()) !== -1;
+ }
+ });
+
+ const activeIndex = searchString ? 0 : -1;
+
+ this.setState({
+ activeIndex,
+ matchedRequests,
+ requestGroups,
+ searchString
+ });
+ });
+ }
+
+ _focusInput () {
+ // Need to focus after the Modal has shown, or else it won't exist yet
+ setTimeout(() => {
+ this.refs.input.focus();
+ });
+ }
+
+ show () {
+ throw new Error('show() not supposed to be called on RequestSwitcherModal');
+ }
+
+ toggle () {
+ super.toggle();
+ this._focusInput();
+ this._handleChange('');
+ }
+
+ componentDidMount () {
+ super.componentDidMount();
+
+ ReactDOM.findDOMNode(this.refs.modal).addEventListener('keydown', e => {
+ const keyCode = e.keyCode;
+
+ if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) {
+ // Up or Shift+Tab
+ this._setActiveIndex(this.state.activeIndex - 1);
+ } else if (keyCode === 40 || keyCode === 9) {
+ // Down or Tab
+ this._setActiveIndex(this.state.activeIndex + 1);
+ } else if (keyCode === 13) {
+ // Enter
+ this._activateCurrentIndex();
+ } else {
+ return;
+ }
+
+ e.preventDefault();
+ })
+ }
+
+ render () {
+ const {matchedRequests, requestGroups, searchString, activeIndex} = this.state;
+
return (
-
- Switch Request
-
- DO IT
+
+
+
+ tab or
+
+ ↑ ↓ to navigate
+
+ ↵ to select
+
+ esc to dismiss
+
+ Jump To Request
+
+
+
+ this._handleChange(e.target.value)}
+ />
+
+
+ {matchedRequests.map((r, i) => {
+ const requestGroup = requestGroups.find(rg => rg._id === r.parentId);
+
+ return (
+ -
+
+
+ )
+ })}
+
+
+ {matchedRequests.length === 0 ? (
+
+
+ No matches found for {searchString}
+
+
+
+ ) : null}
-
-
);
}
}
-RequestSwitcherModal.propTypes = {};
+RequestSwitcherModal.propTypes = {
+ activateRequest: PropTypes.func.isRequired,
+ activeRequest: PropTypes.object.isRequired,
+ workspaceId: PropTypes.string.isRequired
+};
export default RequestSwitcherModal;
diff --git a/app/components/base/Input.js b/app/components/base/Input.js
index a08c3c8eaf..1b599d145e 100644
--- a/app/components/base/Input.js
+++ b/app/components/base/Input.js
@@ -27,6 +27,10 @@ class Input extends Component {
} else {
this.refs.input.value = this.props.value || '';
}
+
+ if (this.props.autofocus) {
+ this.focus();
+ }
}
componentDidMount () {
@@ -34,7 +38,7 @@ class Input extends Component {
}
componentDidUpdate () {
- this._updateValueFromProps()
+ this._updateValueFromProps();
}
focus () {
@@ -46,7 +50,8 @@ class Input extends Component {
}
render () {
- const {value, ...other} = this.props;
+ // NOTE: We're taking props base doesn't need
+ const {value, autofocus, ...other} = this.props;
return (
(
-
-
- {children}
-
-);
+const ModalHeader = ({hideCloseButton, className, children}) => {
+ let closeButton = null;
+
+ if (!hideCloseButton) {
+ closeButton = (
+
+ )
+ }
+
+ return (
+
+ {closeButton}
+ {children}
+
+ );
+};
+
+ModalHeader.propTypes = {
+ hideCloseButton: PropTypes.bool
+};
export default ModalHeader;
diff --git a/app/containers/App.js b/app/containers/App.js
index 514a22dac0..1fe899dfdf 100644
--- a/app/containers/App.js
+++ b/app/containers/App.js
@@ -150,11 +150,17 @@ class App extends Component {
console.warn('-- Recreating Sort Keys --');
requestGroups.map((r, i) => {
- db.requestGroupUpdate(r, {metaSortKey: i * 100, parentId: requestGroupToTarget.parentId});
+ db.requestGroupUpdate(r, {
+ metaSortKey: i * 100,
+ parentId: requestGroupToTarget.parentId
+ });
});
} else {
const metaSortKey = afterKey - (afterKey - beforeKey) / 2;
- db.requestGroupUpdate(requestGroupToMove, {metaSortKey, parentId: requestGroupToTarget.parentId});
+ db.requestGroupUpdate(requestGroupToMove, {
+ metaSortKey,
+ parentId: requestGroupToTarget.parentId
+ });
}
break;
@@ -226,7 +232,7 @@ class App extends Component {
if (a.metaSortKey === b.metaSortKey) {
return a._id > b._id ? -1 : 1;
} else {
- return a.metaSortKey < b.metaSortKey ? -1 : 1;
+ return a.metaSortKey < b.metaSortKey ? -1 : 1;
}
});
@@ -485,8 +491,12 @@ class App extends Component {
-
+ db.workspaceUpdate(workspace, {metaActiveRequestId: r._id})}
+ />
db.requestGroupUpdate(rg)}/>
)
diff --git a/app/css/components/dropdown.scss b/app/css/components/dropdown.scss
index feac887497..2b2fc54d30 100644
--- a/app/css/components/dropdown.scss
+++ b/app/css/components/dropdown.scss
@@ -72,14 +72,12 @@
.dropdown__divider__label {
position: relative;
- top: -0.85rem;
+ top: -0.80rem;
// HACK: Fine adjustment
- color: $hl-xxl;
+ color: $hl;
padding-right: 1em;
background: #fff;
font-size: $font-size-xs;
- margin-top: 0.5em;
- margin-bottom: 0.5em;
text-transform: uppercase;
}
}
diff --git a/app/css/components/forms.scss b/app/css/components/forms.scss
index 8a80f20a68..ad1f346a95 100644
--- a/app/css/components/forms.scss
+++ b/app/css/components/forms.scss
@@ -75,6 +75,8 @@ label > .form-control,
}
}
+.btn:focus:not(:disabled),
+.btn.focus:not(:disabled),
.btn:hover:not(:disabled) {
background: $hl-sm;
}
diff --git a/app/css/components/modal.scss b/app/css/components/modal.scss
index 7a7b13147c..1694c6d668 100644
--- a/app/css/components/modal.scss
+++ b/app/css/components/modal.scss
@@ -45,6 +45,10 @@
max-height: 100%;
}
+ &.modal--fixed-top .modal__content {
+ margin: 0 auto auto auto;
+ }
+
.modal__header {
border-bottom: 1px solid $hl-md;
height: $line-height-md;
diff --git a/app/css/components/requestswitcher.scss b/app/css/components/requestswitcher.scss
new file mode 100644
index 0000000000..22d95e3170
--- /dev/null
+++ b/app/css/components/requestswitcher.scss
@@ -0,0 +1,22 @@
+@import '../constants/dimensions';
+@import '../constants/colors';
+
+.request-switcher {
+ ul {
+
+ }
+
+ .btn:hover {
+ background: $hl-xs;
+ }
+
+ .btn.focus {
+ background: $hl-sm;
+ }
+
+ .tag {
+ width: 3em;
+ text-align: left;
+ padding-left: 0 !important;
+ }
+}
diff --git a/app/css/constants/colors.scss b/app/css/constants/colors.scss
index b712220ac5..43d39ae9cb 100644
--- a/app/css/constants/colors.scss
+++ b/app/css/constants/colors.scss
@@ -26,7 +26,7 @@ $hl-xl: rgba(140, 140, 140, 0.5);
$hl-xxl: rgba(140, 140, 140, 0.7);
$hl: rgba(140, 140, 140, 1);
-$success: #8fc62b;
+$success: #88bd29;
$notice: #e5df54;
$warning: #ffb932;
$danger: #ff6d59;
diff --git a/app/css/index.scss b/app/css/index.scss
index 45b24b02e4..855087a992 100644
--- a/app/css/index.scss
+++ b/app/css/index.scss
@@ -14,6 +14,7 @@
/* Components */
@import 'components/wrapper';
+@import 'components/requestswitcher';
@import 'components/changelog';
@import 'components/sidebar';
@import 'components/pane';