Просмотр исходного кода

Merge pull request #1274 from weseek/support/migrate-to-reactstrap

Support/migrate to reactstrap
Yuki Takei 6 лет назад
Родитель
Сommit
8d6b9dcd62
27 измененных файлов с 435 добавлено и 305 удалено
  1. 12 0
      babel.config.js
  2. 1 1
      config/webpack.dev.dll.js
  3. 4 3
      package.json
  4. 3 2
      src/client/js/app.jsx
  5. 2 1
      src/client/js/components/InstallerForm.jsx
  6. 4 3
      src/client/js/components/MyDraftList/Draft.jsx
  7. 2 1
      src/client/js/components/MyDraftList/MyDraftList.jsx
  8. 80 65
      src/client/js/components/Page/CopyDropdown.jsx
  9. 12 10
      src/client/js/components/Page/TagEditor.jsx
  10. 2 2
      src/client/js/components/PageAttachment.jsx
  11. 13 10
      src/client/js/components/PageAttachment/DeleteAttachmentModal.jsx
  12. 10 6
      src/client/js/components/PageComment/Comment.jsx
  13. 12 6
      src/client/js/components/PageComment/CommentEditor.jsx
  14. 12 11
      src/client/js/components/PageComment/DeleteCommentModal.jsx
  15. 7 3
      src/client/js/components/PageComments.jsx
  16. 12 10
      src/client/js/components/PageEditor/CodeMirrorEditor.jsx
  17. 20 16
      src/client/js/components/PageEditor/HandsontableModal.jsx
  18. 14 8
      src/client/js/components/PageEditor/MarkdownTableDataImportForm.jsx
  19. 36 53
      src/client/js/components/PageEditor/OptionsSelector.jsx
  20. 2 1
      src/client/js/components/RecentCreated/RecentCreated.jsx
  21. 18 15
      src/client/js/components/SavePageControls/GrantSelector.jsx
  22. 16 12
      src/client/js/components/SearchPage/DeletePageListModal.jsx
  23. 3 1
      src/client/js/components/TagsList.jsx
  24. 3 2
      src/client/js/components/User/UserPictureList.jsx
  25. 0 2
      src/client/styles/scss/_search.scss
  26. 3 0
      src/client/styles/scss/_vendor.scss
  27. 132 61
      yarn.lock

+ 12 - 0
babel.config.js

@@ -14,6 +14,18 @@ module.exports = function(api) {
   ];
   const plugins = [
     'lodash',
+    // transform
+    //  from `import { Button } from 'reactstrap';`
+    //  to   `import Row from 'reactstrap/Button';`
+    [
+      'transform-imports', {
+        reactstrap: {
+          // eslint-disable-next-line no-template-curly-in-string
+          transform: 'reactstrap/es/${member}',
+          preventFullImport: true,
+        },
+      },
+    ],
   ];
 
   return {

+ 1 - 1
config/webpack.dev.dll.js

@@ -23,7 +23,7 @@ module.exports = {
       'lodash', 'pako',
       'markdown-it', 'csv-to-markdown-table',
       'react', 'react-dom',
-      'react-bootstrap', 'react-bootstrap-typeahead',
+      'reactstrap', 'react-bootstrap-typeahead',
       'react-i18next', 'react-dropzone', 'react-hotkeys', 'react-copy-to-clipboard', 'react-waypoint',
       'socket.io-client',
       'toastr',

+ 4 - 3
package.json

@@ -148,8 +148,9 @@
     "babel-eslint": "^10.0.1",
     "babel-loader": "^8.0.6",
     "babel-plugin-lodash": "^3.3.4",
+    "babel-plugin-transform-imports": "^2.0.0",
     "bootstrap": "^4.3.1",
-    "bootstrap-select": "^1.12.4",
+    "bootstrap-select": "^1.13.11",
     "browser-bunyan": "^1.3.0",
     "browser-sync": "^2.26.3",
     "bunyan-debug": "^2.0.0",
@@ -202,8 +203,7 @@
     "postcss-loader": "^3.0.0",
     "prettier-stylelint": "^0.4.2",
     "react": "^16.8.3",
-    "react-bootstrap": "^0.32.1",
-    "react-bootstrap-typeahead": "^3.4.2",
+    "react-bootstrap-typeahead": "^3.4.7",
     "react-codemirror2": "^6.0.0",
     "react-copy-to-clipboard": "^5.0.1",
     "react-dom": "^16.8.3",
@@ -212,6 +212,7 @@
     "react-hotkeys": "^2.0.0",
     "react-i18next": "^10.6.1",
     "react-waypoint": "^9.0.0",
+    "reactstrap": "^8.0.1",
     "replacestream": "^4.0.3",
     "reveal.js": "^3.5.0",
     "sass-loader": "^8.0.0",

+ 3 - 2
src/client/js/app.jsx

@@ -112,8 +112,9 @@ if (pageContainer.state.pageId != null) {
     'page-comment-write':  <CommentEditorLazyRenderer />,
     'revision-toc': <TableOfContents />,
     'like-button': <LikeButton pageId={pageContainer.state.pageId} isLiked={pageContainer.state.isLiked} />,
-    'seen-user-list': <UserPictureList userIds={pageContainer.state.seenUserIds} />,
-    'liker-list': <UserPictureList userIds={pageContainer.state.likerUserIds} />,
+    // TODO: GW-333
+    // 'seen-user-list': <UserPictureList userIds={pageContainer.state.seenUserIds} />,
+    // 'liker-list': <UserPictureList userIds={pageContainer.state.likerUserIds} />,
     'bookmark-button':  <BookmarkButton pageId={pageContainer.state.pageId} crowi={appContainer} />,
     'bookmark-button-lg':  <BookmarkButton pageId={pageContainer.state.pageId} crowi={appContainer} size="lg" />,
     'rename-page-name-input':  <PagePathAutoComplete crowi={appContainer} initializedPath={pageContainer.state.path} />,

+ 2 - 1
src/client/js/components/InstallerForm.jsx

@@ -4,7 +4,8 @@ import PropTypes from 'prop-types';
 import i18next from 'i18next';
 import { withTranslation } from 'react-i18next';
 
-import Radio from 'react-bootstrap/es/Radio';
+// FIXME: use native Bootstrap 4 or reactstrap
+// import Radio from 'react-bootstrap/es/Radio';
 
 class InstallerForm extends React.Component {
 

+ 4 - 3
src/client/js/components/MyDraftList/Draft.jsx

@@ -4,9 +4,10 @@ import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 
-import Panel from 'react-bootstrap/es/Panel';
-import Tooltip from 'react-bootstrap/es/Tooltip';
-import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
+// TODO: GW-333
+// import Panel from 'react-bootstrap/es/Panel';
+// import Tooltip from 'react-bootstrap/es/Tooltip';
+// import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import AppContainer from '../../services/AppContainer';

+ 2 - 1
src/client/js/components/MyDraftList/MyDraftList.jsx

@@ -3,7 +3,8 @@ import PropTypes from 'prop-types';
 
 import { withTranslation } from 'react-i18next';
 
-import Pagination from 'react-bootstrap/lib/Pagination';
+// TODO: GW-333
+// import Pagination from 'react-bootstrap/lib/Pagination';
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import AppContainer from '../../services/AppContainer';

+ 80 - 65
src/client/js/components/Page/CopyDropdown.jsx

@@ -1,8 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Dropdown from 'react-bootstrap/es/Dropdown';
-import MenuItem from 'react-bootstrap/es/MenuItem';
+import {
+  Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
+  Tooltip,
+} from 'reactstrap';
 
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 
@@ -14,14 +16,24 @@ export default class CopyDropdown extends React.Component {
     // retrieve xss library from window
     this.xss = window.xss;
 
+    this.state = {
+      dropdownOpen: false,
+      tooltipOpen: false,
+    };
+
+    this.toggle = this.toggle.bind(this);
+    this.showToolTip = this.showToolTip.bind(this);
     this.generatePageUrl = this.generatePageUrl.bind(this);
   }
 
+  toggle() {
+    this.setState({ dropdownOpen: !this.state.dropdownOpen });
+  }
+
   showToolTip() {
-    const buttonId = '#copyPagePathDropdown';
-    $(buttonId).tooltip('show');
+    this.setState({ tooltipOpen: true });
     setTimeout(() => {
-      $(buttonId).tooltip('hide');
+      this.setState({ tooltipOpen: false });
     }, 1000);
   }
 
@@ -42,69 +54,72 @@ export default class CopyDropdown extends React.Component {
     const url = this.generatePageUrl();
 
     return (
-      <Dropdown id="copyPagePathDropdown">
-
-        <Dropdown.Toggle
-          className="btn-copy"
-          style={this.props.buttonStyle}
-          data-toggle="tooltip"
-          data-placement="bottom"
-          data-trigger="manual"
-          title="copied!"
-        >
-          <i className="ti-clipboard"></i>
-        </Dropdown.Toggle>
-
-        <Dropdown.Menu>
-          <h5 className="ml-3 my-0 text-muted">{ t('copy_to_clipboard.Copy to clipboard') }</h5>
-          <MenuItem divider></MenuItem>
-
-          {/* Page path */}
-          <CopyToClipboard text={this.props.pagePath} onCopy={this.showToolTip}>
-            <MenuItem>
-              <div className="d-inline-flex flex-column">
-                <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Page path') }</strong></h6>
-                <span className="small">{safePagePath}</span>
-              </div>
-            </MenuItem>
-          </CopyToClipboard>
-          {/* Parmanent Link */}
-          { this.props.pageId && (
-            <CopyToClipboard text={url} onCopy={this.showToolTip}>
-              <MenuItem>
-                <div className="d-inline-flex flex-column">
-                  <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Parmanent link') }</strong></h6>
-                  <span className="small">{url}</span>
-                </div>
-              </MenuItem>
-            </CopyToClipboard>
-          )}
-          {/* Page path + Parmanent Link */}
-          { this.props.pageId && (
-            <CopyToClipboard text={`${this.props.pagePath}\n${url}`} onCopy={this.showToolTip}>
-              <MenuItem>
+      <>
+        <Dropdown id="copyPagePathDropdown" isOpen={this.state.dropdownOpen} toggle={this.toggle}>
+
+          <DropdownToggle
+            caret
+            className="btn-copy"
+            style={this.props.buttonStyle}
+          >
+            <i className="ti-clipboard"></i>
+          </DropdownToggle>
+
+          <DropdownMenu>
+            <h5 className="ml-3 my-0 text-muted">{ t('copy_to_clipboard.Copy to clipboard') }</h5>
+            <DropdownItem divider></DropdownItem>
+
+            {/* Page path */}
+            <CopyToClipboard text={this.props.pagePath} onCopy={this.showToolTip}>
+              <DropdownItem>
                 <div className="d-inline-flex flex-column">
-                  <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Page path and parmanent link') }</strong></h6>
-                  <span className="small mb-1">{safePagePath}</span><br></br>
-                  <span className="small">{url}</span>
+                  <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Page path') }</strong></h6>
+                  <span className="small">{safePagePath}</span>
                 </div>
-              </MenuItem>
+              </DropdownItem>
             </CopyToClipboard>
-          )}
-          {/* Markdown Link */}
-          { this.props.pageId && (
-            <CopyToClipboard text={`[${this.props.pagePath}](${url})`} onCopy={this.showToolTip}>
-              <MenuItem>
-                <div className="d-inline-flex flex-column">
-                  <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Markdown link') }</strong></h6>
-                  <span className="small">{`[${safePagePath}](${url})`}</span>
-                </div>
-              </MenuItem>
-            </CopyToClipboard>
-          )}
-        </Dropdown.Menu>
-
-      </Dropdown>
+            {/* Parmanent Link */}
+            { this.props.pageId && (
+              <CopyToClipboard text={url} onCopy={this.showToolTip}>
+                <DropdownItem>
+                  <div className="d-inline-flex flex-column">
+                    <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Parmanent link') }</strong></h6>
+                    <span className="small">{url}</span>
+                  </div>
+                </DropdownItem>
+              </CopyToClipboard>
+            )}
+            {/* Page path + Parmanent Link */}
+            { this.props.pageId && (
+              <CopyToClipboard text={`${this.props.pagePath}\n${url}`} onCopy={this.showToolTip}>
+                <DropdownItem>
+                  <div className="d-inline-flex flex-column">
+                    <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Page path and parmanent link') }</strong></h6>
+                    <span className="small mb-1">{safePagePath}</span><br></br>
+                    <span className="small">{url}</span>
+                  </div>
+                </DropdownItem>
+              </CopyToClipboard>
+            )}
+            {/* Markdown Link */}
+            { this.props.pageId && (
+              <CopyToClipboard text={`[${this.props.pagePath}](${url})`} onCopy={this.showToolTip}>
+                <DropdownItem>
+                  <div className="d-inline-flex flex-column">
+                    <h6 className="mt-1 mb-2"><strong>{ t('copy_to_clipboard.Markdown link') }</strong></h6>
+                    <span className="small">{`[${safePagePath}](${url})`}</span>
+                  </div>
+                </DropdownItem>
+              </CopyToClipboard>
+            )}
+          </DropdownMenu>
+
+        </Dropdown>
+
+        <Tooltip placement="bottom" isOpen={this.state.tooltipOpen} target="copyPagePathDropdown" fade={false}>
+          copied!
+        </Tooltip>
+      </>
     );
   }
 

+ 12 - 10
src/client/js/components/Page/TagEditor.jsx

@@ -1,7 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import Button from 'react-bootstrap/es/Button';
-import Modal from 'react-bootstrap/es/Modal';
+
+import {
+  Button, Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
 
 import AppContainer from '../../services/AppContainer';
 
@@ -44,18 +46,18 @@ export default class TagEditor extends React.Component {
 
   render() {
     return (
-      <Modal show={this.state.isOpenModal} onHide={this.closeModalHandler} id="editTagModal">
-        <Modal.Header closeButton className="bg-primary">
-          <Modal.Title className="text-white">Edit Tags</Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
+      <Modal isOpen={this.state.isOpenModal} toggle={this.closeModalHandler} id="editTagModal">
+        <ModalHeader closeButton className="bg-primary">
+          <span className="text-white">Edit Tags</span>
+        </ModalHeader>
+        <ModalBody>
           <TagsInput tags={this.state.tags} onTagsUpdated={this.onTagsUpdatedByTagsInput} />
-        </Modal.Body>
-        <Modal.Footer>
+        </ModalBody>
+        <ModalFooter>
           <Button variant="primary" onClick={this.handleSubmit}>
             Done
           </Button>
-        </Modal.Footer>
+        </ModalFooter>
       </Modal>
     );
   }

+ 2 - 2
src/client/js/components/PageAttachment.jsx

@@ -108,9 +108,9 @@ class PageAttachment extends React.Component {
 
       deleteAttachmentModal = (
         <DeleteAttachmentModal
-          show={showModal}
+          isOpen={showModal}
           animation={false}
-          onHide={deleteModalClose}
+          toggle={deleteModalClose}
 
           attachmentToDelete={attachmentToDelete}
           inUse={deleteInUse}

+ 13 - 10
src/client/js/components/PageAttachment/DeleteAttachmentModal.jsx

@@ -1,7 +1,10 @@
 /* eslint-disable react/prop-types */
 import React from 'react';
-import Button from 'react-bootstrap/es/Button';
-import Modal from 'react-bootstrap/es/Modal';
+
+import {
+  Button,
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
 
 import UserPicture from '../User/UserPicture';
 import Username from '../User/Username';
@@ -70,23 +73,23 @@ export default class DeleteAttachmentModal extends React.Component {
 
     return (
       <Modal {...props} className="attachment-delete-modal" bsSize="large" aria-labelledby="contained-modal-title-lg">
-        <Modal.Header closeButton>
-          <Modal.Title id="contained-modal-title-lg">Delete attachment?</Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
+        <ModalHeader closeButton>
+          <span id="contained-modal-title-lg">Delete attachment?</span>
+        </ModalHeader>
+        <ModalBody>
           {renderAttachment}
-        </Modal.Body>
-        <Modal.Footer>
+        </ModalBody>
+        <ModalFooter>
           <div className="mr-3 d-inline-block">
             {deletingIndicator}
           </div>
           <Button
+            color="danger"
             onClick={this._onDeleteConfirm}
-            bsStyle="danger"
             disabled={this.props.deleting}
           >Delete!
           </Button>
-        </Modal.Footer>
+        </ModalFooter>
       </Modal>
     );
   }

+ 10 - 6
src/client/js/components/PageComment/Comment.jsx

@@ -3,10 +3,14 @@ import PropTypes from 'prop-types';
 
 import { format, formatDistanceStrict } from 'date-fns';
 
-import Button from 'react-bootstrap/es/Button';
-import Tooltip from 'react-bootstrap/es/Tooltip';
-import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
-import Collapse from 'react-bootstrap/es/Collapse';
+// TODO: GW-333
+// import Tooltip from 'react-bootstrap/es/Tooltip';
+// import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
+
+import {
+  Button,
+  Collapse,
+} from 'reactstrap';
 
 import AppContainer from '../../services/AppContainer';
 import PageContainer from '../../services/PageContainer';
@@ -202,7 +206,7 @@ class Comment extends React.Component {
     const toggleButtonLabel = isOlderRepliesShown ? '' : 'more';
     const toggleButton = (
       <Button
-        bsStyle="link"
+        color="link"
         className="page-comments-list-toggle-older"
         onClick={() => { this.setState({ isOlderRepliesShown: !isOlderRepliesShown }) }}
       >
@@ -225,7 +229,7 @@ class Comment extends React.Component {
       <React.Fragment>
         { areThereHiddenReplies && (
           <div className="page-comments-hidden-replies">
-            <Collapse in={this.state.isOlderRepliesShown}>
+            <Collapse isOpen={this.state.isOlderRepliesShown}>
               <div>{hiddenElements}</div>
             </Collapse>
             <div className="text-center">{toggleButton}</div>

+ 12 - 6
src/client/js/components/PageComment/CommentEditor.jsx

@@ -1,9 +1,14 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Button from 'react-bootstrap/es/Button';
-import Tab from 'react-bootstrap/es/Tab';
-import Tabs from 'react-bootstrap/es/Tabs';
+// TODO: GW-333
+// import Tab from 'react-bootstrap/es/Tab';
+// import Tabs from 'react-bootstrap/es/Tabs';
+
+import {
+  Button,
+} from 'reactstrap';
+
 import * as toastr from 'toastr';
 
 import AppContainer from '../../services/AppContainer';
@@ -222,8 +227,9 @@ class CommentEditor extends React.Component {
     const errorMessage = <span className="text-danger text-right mr-2">{this.state.errorMessage}</span>;
     const submitButton = (
       <Button
-        bsStyle="primary"
-        className="fcbtn btn btn-primary btn-outline btn-rounded btn-1b"
+        outline
+        color="primary"
+        className="fcbtn btn-rounded btn-1b"
         onClick={this.postHandler}
       >
         Comment
@@ -296,7 +302,7 @@ class CommentEditor extends React.Component {
                   )
                 }
                 <div>
-                  <Button bsStyle="danger" className="fcbtn btn btn-xs btn-danger btn-outline btn-rounded" onClick={this.toggleEditor}>
+                  <Button outline color="danger" size="xs" className="fcbtn btn-rounded" onClick={this.toggleEditor}>
                     Cancel
                   </Button>
                 </div>

+ 12 - 11
src/client/js/components/PageComment/DeleteCommentModal.jsx

@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Button from 'react-bootstrap/es/Button';
-import Modal from 'react-bootstrap/es/Modal';
+import {
+  Button, Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
 
 import { format } from 'date-fns';
 
@@ -35,25 +36,25 @@ export default class DeleteCommentModal extends React.Component {
     commentBody = <span style={{ whiteSpace: 'pre-wrap' }}>{commentBody}</span>;
 
     return (
-      <Modal show={this.props.isShown} onHide={this.props.cancel} className="page-comment-delete-modal">
-        <Modal.Header closeButton>
-          <Modal.Title>
+      <Modal isOpen={this.props.isShown} toggle={this.props.cancel} className="page-comment-delete-modal">
+        <ModalHeader toggle={this.props.cancel}>
+          <span>
             <i className="icon-fw icon-fire text-danger"></i>
             Delete comment?
-          </Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
+          </span>
+        </ModalHeader>
+        <ModalBody>
           <UserPicture user={comment.creator} size="xs" /> <strong><Username user={comment.creator}></Username></strong> wrote on {commentDate}:
           <p className="well well-sm comment-body m-t-5">{commentBody}</p>
-        </Modal.Body>
-        <Modal.Footer>
+        </ModalBody>
+        <ModalFooter>
           <span className="text-danger">{this.props.errorMessage}</span>&nbsp;
           <Button onClick={this.props.cancel} bsClass="btn btn-sm">Cancel</Button>
           <Button onClick={this.props.confirmedToDelete} bsClass="btn btn-sm btn-danger">
             <i className="icon icon-fire"></i>
             Delete
           </Button>
-        </Modal.Footer>
+        </ModalFooter>
       </Modal>
     );
   }

+ 7 - 3
src/client/js/components/PageComments.jsx

@@ -1,7 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Button from 'react-bootstrap/es/Button';
+import {
+  Button,
+} from 'reactstrap';
 
 import { withTranslation } from 'react-i18next';
 
@@ -146,8 +148,10 @@ class PageComments extends React.Component {
         { !showEditor && isLoggedIn && (
           <div className="text-right">
             <Button
-              bsStyle="default"
-              className="btn btn-outline btn-default btn-sm btn-comment-reply"
+              outline
+              color="secondary"
+              size="sm"
+              className="btn-comment-reply"
               onClick={() => { return this.replyButtonClickedHandler(commentId) }}
             >
               <i className="icon-fw icon-action-redo"></i> Reply

+ 12 - 10
src/client/js/components/PageEditor/CodeMirrorEditor.jsx

@@ -1,11 +1,13 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Modal from 'react-bootstrap/es/Modal';
-import Button from 'react-bootstrap/es/Button';
 import urljoin from 'url-join';
 import * as codemirror from 'codemirror';
 
+import {
+  Button, Modal, ModalHeader, ModalBody,
+} from 'reactstrap';
+
 import { UnControlled as ReactCodeMirror } from 'react-codemirror2';
 
 import InterceptorManager from '@commons/service/interceptor-manager';
@@ -551,20 +553,20 @@ export default class CodeMirrorEditor extends AbstractEditor {
     };
 
     return (
-      <React.Fragment>
-        <Modal className="modal-gfm-cheatsheet" show={this.state.isCheatsheetModalShown} onHide={() => { hideCheatsheetModal() }}>
-          <Modal.Header closeButton>
-            <Modal.Title><i className="icon-fw icon-question" />Markdown Help</Modal.Title>
-          </Modal.Header>
-          <Modal.Body className="pt-1">
+      <>
+        <Modal className="modal-gfm-cheatsheet" isOpen={this.state.isCheatsheetModalShown} toggle={() => { hideCheatsheetModal() }}>
+          <ModalHeader toggle={() => { hideCheatsheetModal() }}>
+            <i className="icon-fw icon-question" />Markdown Help
+          </ModalHeader>
+          <ModalBody className="pt-1">
             { this.renderCheatsheetModalBody() }
-          </Modal.Body>
+          </ModalBody>
         </Modal>
 
         <button type="button" className="btn-link gfm-cheatsheet-modal-link text-muted small mr-3" onClick={() => { showCheatsheetModal() }}>
           <i className="icon-question" /> Markdown
         </button>
-      </React.Fragment>
+      </>
     );
   }
 

+ 20 - 16
src/client/js/components/PageEditor/HandsontableModal.jsx

@@ -1,13 +1,17 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import Modal from 'react-bootstrap/es/Modal';
-import Button from 'react-bootstrap/es/Button';
-import ButtonGroup from 'react-bootstrap/es/ButtonGroup';
-import Collapse from 'react-bootstrap/es/Collapse';
+
+import {
+  Button, ButtonGroup,
+  Collapse,
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
+
 import Handsontable from 'handsontable';
 import { HotTable } from '@handsontable/react';
 import { debounce } from 'throttle-debounce';
 
+
 import MarkdownTableDataImportForm from './MarkdownTableDataImportForm';
 import MarkdownTable from '../../models/MarkdownTable';
 
@@ -412,12 +416,12 @@ export default class HandsontableModal extends React.PureComponent {
     const dialogClassName = dialogClassNames.join(' ');
 
     return (
-      <Modal show={this.state.show} onHide={this.cancel} bsSize="large" dialogClassName={dialogClassName}>
-        <Modal.Header closeButton>
+      <Modal isOpen={this.state.show} toggle={this.cancel} bsSize="large" dialogClassName={dialogClassName}>
+        <ModalHeader toggle={this.cancel}>
           { this.renderExpandOrContractButton() }
-          <Modal.Title>Edit Table</Modal.Title>
-        </Modal.Header>
-        <Modal.Body className="p-0 d-flex flex-column">
+          Edit Table
+        </ModalHeader>
+        <ModalBody className="p-0 d-flex flex-column">
           <div className="px-4 py-3 modal-navbar">
             <Button className="m-r-20 data-import-button" onClick={this.toggleDataImportArea}>
               Data Import<i className={this.state.isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down'}></i>
@@ -427,7 +431,7 @@ export default class HandsontableModal extends React.PureComponent {
               <Button onClick={() => { this.alignButtonHandler('c') }}><i className="ti-align-center"></i></Button>
               <Button onClick={() => { this.alignButtonHandler('r') }}><i className="ti-align-right"></i></Button>
             </ButtonGroup>
-            <Collapse in={this.state.isDataImportAreaExpanded}>
+            <Collapse isOpen={this.state.isDataImportAreaExpanded}>
               <div> {/* This div is necessary for smoothing animations. (https://react-bootstrap.github.io/utilities/transitions/#transitions-collapse) */}
                 <MarkdownTableDataImportForm onCancel={this.toggleDataImportArea} onImport={this.importData} />
               </div>
@@ -447,16 +451,16 @@ export default class HandsontableModal extends React.PureComponent {
               afterColumnMove={this.afterColumnMoveHandler}
             />
           </div>
-        </Modal.Body>
-        <Modal.Footer>
+        </ModalBody>
+        <ModalFooter>
           <div className="d-flex justify-content-between">
-            <Button bsStyle="danger" onClick={this.reset}>Reset</Button>
+            <Button color="danger" onClick={this.reset}>Reset</Button>
             <div className="d-flex">
-              <Button bsStyle="default" onClick={this.cancel}>Cancel</Button>
-              <Button bsStyle="primary" onClick={this.save}>Done</Button>
+              <Button color="secondary" onClick={this.cancel}>Cancel</Button>
+              <Button color="primary" onClick={this.save}>Done</Button>
             </div>
           </div>
-        </Modal.Footer>
+        </ModalFooter>
       </Modal>
     );
   }

+ 14 - 8
src/client/js/components/PageEditor/MarkdownTableDataImportForm.jsx

@@ -1,10 +1,16 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import FormGroup from 'react-bootstrap/es/FormGroup';
-import ControlLabel from 'react-bootstrap/es/ControlLabel';
-import FormControl from 'react-bootstrap/es/FormControl';
-import Button from 'react-bootstrap/es/Button';
-import Collapse from 'react-bootstrap/es/Collapse';
+
+// TODO: GW-333
+// import FormGroup from 'react-bootstrap/es/FormGroup';
+// import ControlLabel from 'react-bootstrap/es/ControlLabel';
+// import FormControl from 'react-bootstrap/es/FormControl';
+
+import {
+  Button,
+  Collapse,
+} from 'reactstrap';
+
 import MarkdownTable from '../../models/MarkdownTable';
 
 export default class MarkdownTableDataImportForm extends React.Component {
@@ -73,15 +79,15 @@ export default class MarkdownTableDataImportForm extends React.Component {
             onChange={(e) => { return this.setState({ data: e.target.value }) }}
           />
         </FormGroup>
-        <Collapse in={this.state.parserErrorMessage != null}>
+        <Collapse isOpen={this.state.parserErrorMessage != null}>
           <FormGroup>
             <ControlLabel>Parse Error</ControlLabel>
             <FormControl componentClass="textarea" style={{ height: 100 }} value={this.state.parserErrorMessage || ''} readOnly />
           </FormGroup>
         </Collapse>
         <div className="d-flex justify-content-end">
-          <Button bsStyle="default" onClick={this.props.onCancel}>Cancel</Button>
-          <Button bsStyle="primary" onClick={this.importButtonHandler}>Import</Button>
+          <Button color="secondary" onClick={this.props.onCancel}>Cancel</Button>
+          <Button color="primary" onClick={this.importButtonHandler}>Import</Button>
         </div>
       </form>
     );

+ 36 - 53
src/client/js/components/PageEditor/OptionsSelector.jsx

@@ -3,12 +3,10 @@ import PropTypes from 'prop-types';
 
 import { withTranslation } from 'react-i18next';
 
-import FormGroup from 'react-bootstrap/es/FormGroup';
-import FormControl from 'react-bootstrap/es/FormControl';
-import ControlLabel from 'react-bootstrap/es/ControlLabel';
-
-import Dropdown from 'react-bootstrap/es/Dropdown';
-import MenuItem from 'react-bootstrap/es/MenuItem';
+import {
+  FormGroup, Label, Input,
+  Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
+} from 'reactstrap';
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import EditorContainer from '../../services/EditorContainer';
@@ -104,9 +102,6 @@ class OptionsSelector extends React.Component {
   onClickRenderMathJaxInRealtime(event) {
     const { editorContainer } = this.props;
 
-    // keep dropdown opened
-    this._cddForceOpen = true;
-
     const newValue = !editorContainer.state.previewOptions.renderMathJaxInRealtime;
     const newOpts = Object.assign(editorContainer.state.previewOptions, { renderMathJaxInRealtime: newValue });
     editorContainer.setState({ previewOptions: newOpts });
@@ -115,17 +110,8 @@ class OptionsSelector extends React.Component {
     editorContainer.saveOptsToLocalStorage();
   }
 
-  /*
-   * see: https://github.com/react-bootstrap/react-bootstrap/issues/1490#issuecomment-207445759
-   */
   onToggleConfigurationDropdown(newValue) {
-    if (this._cddForceOpen) {
-      this.setState({ isCddMenuOpened: true });
-      this._cddForceOpen = false;
-    }
-    else {
-      this.setState({ isCddMenuOpened: newValue });
-    }
+    this.setState({ isCddMenuOpened: !this.state.isCddMenuOpened });
   }
 
   renderThemeSelector() {
@@ -133,24 +119,23 @@ class OptionsSelector extends React.Component {
       return <option key={theme} value={theme}>{theme}</option>;
     });
 
-    const bsClassName = 'form-control-dummy'; // set form-control* to shrink width
-
     return (
-      <FormGroup controlId="formControlsSelect" className="my-0">
-        <ControlLabel>Theme:</ControlLabel>
-        <FormControl
-          componentClass="select"
+      <FormGroup className="my-0">
+        <Label>Theme:</Label>
+        <Input
+          type="select"
+          bsSize="sm"
           placeholder="select"
-          bsClass={bsClassName}
-          className="btn-group-sm selectpicker"
+          className="selectpicker"
+          cssModule={{ width: 'unset' }}
           onChange={this.onChangeTheme}
           // eslint-disable-next-line no-return-assign
-          inputRef={(el) => { return this.themeSelectorInputEl = el }}
+          innerRef={(el) => { return this.themeSelectorInputEl = el }}
         >
 
           {optionElems}
 
-        </FormControl>
+        </Input>
       </FormGroup>
     );
   }
@@ -168,49 +153,47 @@ class OptionsSelector extends React.Component {
       );
     }
 
-    const bsClassName = 'form-control-dummy'; // set form-control* to shrink width
-
     return (
-      <FormGroup controlId="formControlsSelect" className="my-0">
-        <ControlLabel>Keymap:</ControlLabel>
-        <FormControl
-          componentClass="select"
+      <FormGroup className="my-0">
+        <Label>Keymap:</Label>
+        <Input
+          type="select"
+          bsSize="sm"
           placeholder="select"
-          bsClass={bsClassName}
-          className="btn-group-sm selectpicker"
+          className="selectpicker"
           onChange={this.onChangeKeymapMode}
           // eslint-disable-next-line no-return-assign
-          inputRef={(el) => { return this.keymapModeSelectorInputEl = el }}
+          innerRef={(el) => { return this.keymapModeSelectorInputEl = el }}
         >
 
           {optionElems}
 
-        </FormControl>
+        </Input>
       </FormGroup>
     );
   }
 
   renderConfigurationDropdown() {
     return (
-      <FormGroup controlId="formControlsSelect" className="my-0">
+      <FormGroup className="my-0">
 
         <Dropdown
-          dropup
-          id="configurationDropdown"
+          direction="up"
+          bsSize="sm"
           className="configuration-dropdown"
-          open={this.state.isCddMenuOpened}
-          onToggle={this.onToggleConfigurationDropdown}
+          isOpen={this.state.isCddMenuOpened}
+          toggle={this.onToggleConfigurationDropdown}
         >
 
-          <Dropdown.Toggle bsSize="sm">
+          <DropdownToggle caret>
             <i className="icon-settings"></i>
-          </Dropdown.Toggle>
+          </DropdownToggle>
 
-          <Dropdown.Menu>
+          <DropdownMenu>
             {this.renderActiveLineMenuItem()}
             {this.renderRealtimeMathJaxMenuItem()}
-            {/* <MenuItem divider /> */}
-          </Dropdown.Menu>
+            {/* <DropdownItem divider /> */}
+          </DropdownMenu>
 
         </Dropdown>
 
@@ -229,11 +212,11 @@ class OptionsSelector extends React.Component {
     const iconClassName = iconClasses.join(' ');
 
     return (
-      <MenuItem onClick={this.onClickStyleActiveLine}>
+      <DropdownItem toggle={false} onClick={this.onClickStyleActiveLine}>
         <span className="icon-container"></span>
         <span className="menuitem-label">{ t('page_edit.Show active line') }</span>
         <span className="icon-container"><i className={iconClassName}></i></span>
-      </MenuItem>
+      </DropdownItem>
     );
   }
 
@@ -254,11 +237,11 @@ class OptionsSelector extends React.Component {
     const iconClassName = iconClasses.join(' ');
 
     return (
-      <MenuItem onClick={this.onClickRenderMathJaxInRealtime}>
+      <DropdownItem toggle={false} onClick={this.onClickRenderMathJaxInRealtime}>
         <span className="icon-container"><img src="/images/icons/fx.svg" width="14px" alt="fx"></img></span>
         <span className="menuitem-label">MathJax Rendering</span>
         <i className={iconClassName}></i>
-      </MenuItem>
+      </DropdownItem>
     );
   }
 

+ 2 - 1
src/client/js/components/RecentCreated/RecentCreated.jsx

@@ -1,7 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Pagination from 'react-bootstrap/lib/Pagination';
+// TODO: GW-333
+// import Pagination from 'react-bootstrap/lib/Pagination';
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import AppContainer from '../../services/AppContainer';

+ 18 - 15
src/client/js/components/SavePageControls/GrantSelector.jsx

@@ -3,11 +3,15 @@ import PropTypes from 'prop-types';
 
 import { withTranslation } from 'react-i18next';
 
-import FormGroup from 'react-bootstrap/es/FormGroup';
-import FormControl from 'react-bootstrap/es/FormControl';
-import ListGroup from 'react-bootstrap/es/ListGroup';
-import ListGroupItem from 'react-bootstrap/es/ListGroupItem';
-import Modal from 'react-bootstrap/es/Modal';
+// TODO: GW-333
+// import FormGroup from 'react-bootstrap/es/FormGroup';
+// import FormControl from 'react-bootstrap/es/FormControl';
+// import ListGroup from 'react-bootstrap/es/ListGroup';
+// import ListGroupItem from 'react-bootstrap/es/ListGroupItem';
+
+import {
+  Modal, ModalHeader, ModalBody,
+} from 'reactstrap';
 
 import AppContainer from '../../services/AppContainer';
 
@@ -258,17 +262,15 @@ class GrantSelector extends React.Component {
       <Modal
         className="select-grant-group"
         container={this}
-        show={this.state.isSelectGroupModalShown}
-        onHide={this.hideSelectGroupModal}
+        isOpen={this.state.isSelectGroupModalShown}
+        toggle={this.hideSelectGroupModal}
       >
-        <Modal.Header closeButton>
-          <Modal.Title>
-              Select a Group
-          </Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
+        <ModalHeader toggle={this.hideSelectGroupModal}>
+          Select a Group
+        </ModalHeader>
+        <ModalBody>
           {content}
-        </Modal.Body>
+        </ModalBody>
       </Modal>
     );
   }
@@ -276,7 +278,8 @@ class GrantSelector extends React.Component {
   render() {
     return (
       <React.Fragment>
-        { this.renderGrantSelector() }
+        {/* FIXME: activate in GW-412 */}
+        {/* { this.renderGrantSelector() } */}
         { !this.props.disabled && this.renderSelectGroupModal() }
       </React.Fragment>
     );

+ 16 - 12
src/client/js/components/SearchPage/DeletePageListModal.jsx

@@ -1,9 +1,13 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import Button from 'react-bootstrap/es/Button';
-import Modal from 'react-bootstrap/es/Modal';
-import Checkbox from 'react-bootstrap/es/Checkbox';
+// TODO: GW-333
+// import Checkbox from 'react-bootstrap/es/Checkbox';
+
+import {
+  Button,
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
 
 export default class DeletePageListModal extends React.Component {
 
@@ -27,26 +31,26 @@ export default class DeletePageListModal extends React.Component {
     });
 
     return (
-      <Modal show={this.props.isShown} onHide={this.props.cancel} className="page-list-delete-modal">
-        <Modal.Header closeButton>
-          <Modal.Title>Deleting pages:</Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
+      <Modal isOpen={this.props.isShown} toggle={this.props.cancel} className="page-list-delete-modal">
+        <ModalHeader toggle={this.props.cancel}>
+          Deleting pages:
+        </ModalHeader>
+        <ModalBody>
           <ul>
             {listView}
           </ul>
-        </Modal.Body>
-        <Modal.Footer>
+        </ModalBody>
+        <ModalFooter>
           <div className="d-flex justify-content-between">
             <span className="text-danger">{this.props.errorMessage}</span>
             <span className="d-flex align-items-center">
               <Checkbox className="text-danger" onClick={this.props.toggleDeleteCompletely} inline>Delete completely</Checkbox>
               <span className="m-l-10">
-                <Button onClick={this.props.confirmedToDelete}><i className="icon-trash"></i>Delete</Button>
+                <Button color="secondary" onClick={this.props.confirmedToDelete}><i className="icon-trash"></i>Delete</Button>
               </span>
             </span>
           </div>
-        </Modal.Footer>
+        </ModalFooter>
       </Modal>
     );
   }

+ 3 - 1
src/client/js/components/TagsList.jsx

@@ -2,7 +2,9 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 import { withTranslation } from 'react-i18next';
-import Pagination from 'react-bootstrap/lib/Pagination';
+
+// TODO: GW-333
+// import Pagination from 'react-bootstrap/lib/Pagination';
 
 class TagsList extends React.Component {
 

+ 3 - 2
src/client/js/components/User/UserPictureList.jsx

@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
-import Tooltip from 'react-bootstrap/es/Tooltip';
+// TODO: GW-333
+// import OverlayTrigger from 'react-bootstrap/es/OverlayTrigger';
+// import Tooltip from 'react-bootstrap/es/Tooltip';
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import AppContainer from '../../services/AppContainer';

+ 0 - 2
src/client/styles/scss/_search.scss

@@ -1,5 +1,3 @@
-// import react-bootstrap-typeahead
-@import '~react-bootstrap-typeahead/css/Typeahead';
 @import 'layout_variable';
 
 .search-listpage-icon {

+ 3 - 0
src/client/styles/scss/_vendor.scss

@@ -1,6 +1,9 @@
 // import bootstrap
 @import '~bootstrap/scss/bootstrap';
 
+// import react-bootstrap-typeahead
+@import '~react-bootstrap-typeahead/css/Typeahead-bs4';
+
 // import toastr styles
 @import '~toastr/build/toastr';
 

+ 132 - 61
yarn.lock

@@ -682,6 +682,13 @@
   dependencies:
     regenerator-runtime "^0.12.0"
 
+"@babel/runtime@^7.2.0":
+  version "7.6.2"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd"
+  integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==
+  dependencies:
+    regenerator-runtime "^0.13.2"
+
 "@babel/runtime@^7.3.1":
   version "7.4.3"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc"
@@ -751,6 +758,15 @@
     lodash "^4.17.11"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.4":
+  version "7.6.1"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.1.tgz#53abf3308add3ac2a2884d539151c57c4b3ac648"
+  integrity sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
 "@browser-bunyan/console-formatted-stream@^1.3.0":
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/@browser-bunyan/console-formatted-stream/-/console-formatted-stream-1.3.0.tgz#3dc059aa5c1b2a7a1f26e2706e2bdeb9a09bbe57"
@@ -1831,6 +1847,14 @@ babel-plugin-lodash@^3.3.4:
     lodash "^4.17.10"
     require-package-name "^2.0.1"
 
+babel-plugin-transform-imports@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-imports/-/babel-plugin-transform-imports-2.0.0.tgz#9e5f49f751a9d34ba8f4bb988c7e48ed2419c6b6"
+  integrity sha512-65ewumYJ85QiXdcB/jmiU0y0jg6eL6CdnDqQAqQ8JMOKh1E52VPG3NJzbVKWcgovUR5GBH8IWpCXQ7I8Q3wjgw==
+  dependencies:
+    "@babel/types" "^7.4"
+    is-valid-path "^0.1.1"
+
 babel-preset-jest@^24.6.0:
   version "24.6.0"
   resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984"
@@ -1839,13 +1863,6 @@ babel-preset-jest@^24.6.0:
     "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
     babel-plugin-jest-hoist "^24.6.0"
 
-babel-runtime@^6.11.6:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
-  dependencies:
-    core-js "^2.4.0"
-    regenerator-runtime "^0.11.0"
-
 backo2@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@@ -2015,11 +2032,10 @@ boom@5.x.x:
   dependencies:
     hoek "4.x.x"
 
-bootstrap-select@^1.12.4:
-  version "1.12.4"
-  resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.12.4.tgz#7f15d3c0ce978868d9c09c70f96624f55fa02ee1"
-  dependencies:
-    jquery ">=1.8"
+bootstrap-select@^1.13.11:
+  version "1.13.11"
+  resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.13.11.tgz#d364ccc67cd6c1f9158689087f1d2d029df82c29"
+  integrity sha512-WPpx2DYL9jVilNoqy4Pjcfa/Q0LOq8V0+xws/pmnRDn/deS7OYjo1njvD1Cv0s9/1ZUXt77UypxuloimEnkYsA==
 
 bootstrap@^4.3.1:
   version "4.3.1"
@@ -2644,6 +2660,11 @@ classnames@^2.2.0, classnames@^2.2.5:
   version "2.2.5"
   resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
 
+classnames@^2.2.3:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
+  integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
+
 clean-stack@^1.0.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31"
@@ -3070,7 +3091,7 @@ core-js@^1.0.0:
   version "1.2.7"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
 
-core-js@^2.4.0, core-js@^2.5.0:
+core-js@^2.5.0:
   version "2.5.3"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
 
@@ -3169,12 +3190,13 @@ create-react-context@^0.1.5:
   resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.1.6.tgz#0f425931d907741127acc6e31acb4f9015dd9fdc"
   integrity sha512-eCnYYEUEc5i32LHwpE/W7NlddOB9oHwsPaWtWzYtflNkkwa3IfindIcoXdVWs12zCbwaMCavKNu84EXogVIWHw==
 
-create-react-context@^0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3"
+create-react-context@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c"
+  integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==
   dependencies:
-    fbjs "^0.8.0"
     gud "^1.0.0"
+    warning "^4.0.3"
 
 cross-env@^5.0.5:
   version "5.1.3"
@@ -3691,6 +3713,13 @@ dom-helpers@^3.2.0, dom-helpers@^3.2.1:
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
 
+dom-helpers@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
+  integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
+  dependencies:
+    "@babel/runtime" "^7.1.2"
+
 dom-serializer@0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -5897,7 +5926,7 @@ into-stream@^3.1.0:
     from2 "^2.1.1"
     p-is-promise "^1.1.0"
 
-invariant@^2.1.0, invariant@^2.2.1, invariant@^2.2.2:
+invariant@^2.2.1, invariant@^2.2.2:
   version "2.2.2"
   resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
   dependencies:
@@ -6145,6 +6174,13 @@ is-installed-globally@^0.1.0:
     global-dirs "^0.1.0"
     is-path-inside "^1.0.0"
 
+is-invalid-path@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34"
+  integrity sha1-MHqFWzzxqTi0TqcNLGEQYFNxTzQ=
+  dependencies:
+    is-glob "^2.0.0"
+
 is-npm@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
@@ -6279,6 +6315,13 @@ is-utf8@^0.2.0:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
 
+is-valid-path@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df"
+  integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8=
+  dependencies:
+    is-invalid-path "^0.1.0"
+
 is-whitespace-character@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed"
@@ -6767,7 +6810,7 @@ jquery.cookie@~1.4.1:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jquery.cookie/-/jquery.cookie-1.4.1.tgz#d63dce209eab691fe63316db08ca9e47e0f9385b"
 
-"jquery@>= 1.7", jquery@>=1.8:
+"jquery@>= 1.7":
   version "3.3.1"
   resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
 
@@ -7018,10 +7061,6 @@ kareem@2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.0.tgz#ef33c42e9024dce511eeaf440cd684f3af1fc769"
 
-keycode@^2.1.2:
-  version "2.1.9"
-  resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa"
-
 keygrip@~1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
@@ -7294,6 +7333,16 @@ lodash.isfinite@^3.3.2:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz#fb89b65a9a80281833f0b7478b3a5104f898ebb3"
 
+lodash.isfunction@^3.0.9:
+  version "3.0.9"
+  resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
+  integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
+
+lodash.isobject@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d"
+  integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=
+
 lodash.isplainobject@^4.0.6:
   version "4.0.6"
   resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
@@ -7316,6 +7365,11 @@ lodash.sortby@^4.7.0:
   resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
   integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
 
+lodash.tonumber@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz#0b96b31b35672793eb7f5a63ee791f1b9e9025d9"
+  integrity sha1-C5azGzVnJ5Prf1pj7nkfG56QJdk=
+
 lodash.union@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
@@ -7341,7 +7395,7 @@ lodash@^4.17.10, lodash@^4.17.5:
   version "4.17.10"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
 
-lodash@^4.17.14, lodash@^4.17.15:
+lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -9991,12 +10045,13 @@ rc@^1.1.7:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
-react-bootstrap-typeahead@^3.4.2:
-  version "3.4.2"
-  resolved "https://registry.yarnpkg.com/react-bootstrap-typeahead/-/react-bootstrap-typeahead-3.4.2.tgz#d0090488854a8597387007ced641dd5fbfc901f7"
+react-bootstrap-typeahead@^3.4.7:
+  version "3.4.7"
+  resolved "https://registry.yarnpkg.com/react-bootstrap-typeahead/-/react-bootstrap-typeahead-3.4.7.tgz#27a3f17c6b1351a0c1b321ac133d5e762cf4dc2a"
+  integrity sha512-eUm3hqX12p+iM+1Y0HKF891/ACbKyGep7PsC2pjFGZL48r25Jlv3X2xmV5D8N0wE/YPFZF7iW913tyAlwqjw1Q==
   dependencies:
     classnames "^2.2.0"
-    create-react-context "^0.2.3"
+    create-react-context "^0.3.0"
     escape-string-regexp "^1.0.5"
     invariant "^2.2.1"
     lodash "^4.17.2"
@@ -10006,23 +10061,6 @@ react-bootstrap-typeahead@^3.4.2:
     react-popper "^1.0.0"
     warning "^4.0.1"
 
-react-bootstrap@^0.32.1:
-  version "0.32.1"
-  resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.32.1.tgz#60624c1b48a39d773ef6cce6421a4f33ecc166bb"
-  dependencies:
-    babel-runtime "^6.11.6"
-    classnames "^2.2.5"
-    dom-helpers "^3.2.0"
-    invariant "^2.2.1"
-    keycode "^2.1.2"
-    prop-types "^15.5.10"
-    prop-types-extra "^1.0.1"
-    react-overlays "^0.8.0"
-    react-prop-types "^0.4.0"
-    react-transition-group "^2.0.0"
-    uncontrollable "^4.1.0"
-    warning "^3.0.0"
-
 react-codemirror2@^6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-6.0.0.tgz#180065df57a64026026cde569a9708fdf7656525"
@@ -10079,7 +10117,12 @@ react-is@^16.8.1, react-is@^16.8.4:
   version "16.8.6"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
 
-react-overlays@^0.8.0, react-overlays@^0.8.1:
+react-lifecycles-compat@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+  integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
+react-overlays@^0.8.1:
   version "0.8.3"
   resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.8.3.tgz#fad65eea5b24301cca192a169f5dddb0b20d3ac5"
   dependencies:
@@ -10101,13 +10144,19 @@ react-popper@^1.0.0:
     typed-styles "^0.0.7"
     warning "^4.0.2"
 
-react-prop-types@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0"
+react-popper@^1.3.3:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.4.tgz#f0cd3b0d30378e1f663b0d79bcc8614221652ced"
+  integrity sha512-9AcQB29V+WrBKk6X7p0eojd1f25/oJajVdMZkywIoAV6Ag7hzE1Mhyeup2Q1QnvFRtGQFQvtqfhlEoDAPfKAVA==
   dependencies:
-    warning "^3.0.0"
+    "@babel/runtime" "^7.1.2"
+    create-react-context "^0.3.0"
+    popper.js "^1.14.4"
+    prop-types "^15.6.1"
+    typed-styles "^0.0.7"
+    warning "^4.0.2"
 
-react-transition-group@^2.0.0, react-transition-group@^2.2.0:
+react-transition-group@^2.2.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10"
   dependencies:
@@ -10118,6 +10167,16 @@ react-transition-group@^2.0.0, react-transition-group@^2.2.0:
     prop-types "^15.5.8"
     warning "^3.0.0"
 
+react-transition-group@^2.3.1:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
+  integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
+  dependencies:
+    dom-helpers "^3.4.0"
+    loose-envify "^1.4.0"
+    prop-types "^15.6.2"
+    react-lifecycles-compat "^3.0.4"
+
 react-waypoint@^9.0.0:
   version "9.0.0"
   resolved "https://registry.yarnpkg.com/react-waypoint/-/react-waypoint-9.0.0.tgz#a027deaafa60e3c2c998e78aa3542fa5ffc98afb"
@@ -10135,6 +10194,21 @@ react@^16.8.3:
     prop-types "^15.6.2"
     scheduler "^0.13.3"
 
+reactstrap@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-8.0.1.tgz#0b663c8195f540bc1d6d5dbcbcf73cab56fe7c79"
+  integrity sha512-GvUWEL+a2+3npK1OxTXcNBMHXX4x6uc1KQRzK7yAOl+8sAHTRWqjunvMUfny3oDh8yKVzgqpqQlWWvs1B2HR9A==
+  dependencies:
+    "@babel/runtime" "^7.2.0"
+    classnames "^2.2.3"
+    lodash.isfunction "^3.0.9"
+    lodash.isobject "^3.0.2"
+    lodash.tonumber "^4.0.3"
+    prop-types "^15.5.8"
+    react-lifecycles-compat "^3.0.4"
+    react-popper "^1.3.3"
+    react-transition-group "^2.3.1"
+
 read-pkg-up@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -10328,10 +10402,6 @@ regenerate@^1.4.0:
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
   integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
 
-regenerator-runtime@^0.11.0:
-  version "0.11.1"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
-
 regenerator-runtime@^0.12.0:
   version "0.12.1"
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
@@ -12329,12 +12399,6 @@ ultron@~1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
 
-uncontrollable@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-4.1.0.tgz#e0358291252e1865222d90939b19f2f49f81c1a9"
-  dependencies:
-    invariant "^2.1.0"
-
 underscore@1.8.3:
   version "1.8.3"
   resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
@@ -12723,6 +12787,13 @@ warning@^4.0.1, warning@^4.0.2:
   dependencies:
     loose-envify "^1.0.0"
 
+warning@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+  integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+  dependencies:
+    loose-envify "^1.0.0"
+
 watchpack@^1.6.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"