Antonio-Maranhao closed pull request #1142: Update fauxton/navigation to use
redux
URL: https://github.com/apache/couchdb-fauxton/pull/1142
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/app/addons/fauxton/appwrapper.js b/app/addons/fauxton/appwrapper.js
index fca8a81a1..ea81a678c 100644
--- a/app/addons/fauxton/appwrapper.js
+++ b/app/addons/fauxton/appwrapper.js
@@ -11,16 +11,14 @@
// the License.
import React from 'react';
+import { connect } from 'react-redux';
import GlobalNotificationsContainer from
'./notifications/components/GlobalNotificationsContainer';
import NotificationPanelContainer from
'./notifications/components/NotificationPanelContainer';
import PermanentNotificationContainer from
'./notifications/components/PermanentNotificationContainer';
import NavBar from './navigation/container/NavBar';
-import NavbarActions from './navigation/actions';
-import Stores from './navigation/stores';
+import * as NavbarActions from './navigation/actions';
import classNames from 'classnames';
-const navBarStore = Stores.navBarStore;
-
class ContentWrapper extends React.Component {
constructor(props) {
super(props);
@@ -29,14 +27,14 @@ class ContentWrapper extends React.Component {
};
if (props.router.currentRouteOptions &&
props.router.currentRouteOptions.selectedHeader) {
-
NavbarActions.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
+ this.props.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
}
}
componentDidMount () {
this.props.router.on('new-component', (routerOptions) => {
this.setState({routerOptions});
-
NavbarActions.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
+ this.props.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
});
this.props.router.on('trigger-update', () => {
@@ -55,31 +53,15 @@ class ContentWrapper extends React.Component {
}
}
-export default class App extends React.Component {
+class App extends React.Component {
constructor (props) {
super(props);
- this.state = this.getStoreState();
- }
-
- getStoreState () {
- return {
- isPrimaryNavMinimized: navBarStore.isMinimized()
- };
- }
-
- componentDidMount () {
- navBarStore.on('change', this.onChange, this);
- }
-
- onChange () {
- this.setState(this.getStoreState());
}
render () {
const mainClass = classNames(
- {'closeMenu': this.state.isPrimaryNavMinimized}
+ {'closeMenu': this.props.isPrimaryNavMinimized}
);
-
return (
<div>
<PermanentNotificationContainer />
@@ -91,7 +73,7 @@ export default class App extends React.Component {
<div id="app-container">
<div className="wrapper">
<div className="pusher">
- <ContentWrapper router={this.props.router} />
+ <ContentWrapper router={this.props.router}
setNavbarActiveLink={this.props.setNavbarActiveLink}/>
</div>
<div id="primary-navbar">
<NavBar/>
@@ -103,3 +85,15 @@ export default class App extends React.Component {
);
}
}
+
+export default connect(
+ ({ navigation }) => {
+ return {
+ isPrimaryNavMinimized: navigation.isMinimized};
+ },
+ (dispatch) => {
+ return {
+ setNavbarActiveLink: (link) => {
dispatch(NavbarActions.setNavbarActiveLink(link)); }
+ };
+ }
+)(App);
diff --git a/app/addons/fauxton/base.js b/app/addons/fauxton/base.js
index 8a3f41784..a1bb98e90 100644
--- a/app/addons/fauxton/base.js
+++ b/app/addons/fauxton/base.js
@@ -12,7 +12,8 @@
import app from '../../app';
import FauxtonAPI from '../../core/api';
-import NavigationActions from './navigation/actions';
+import * as NavigationActions from './navigation/actions';
+import navigationReducers from './navigation/reducers';
import notificationsReducer from './notifications/reducers';
import './assets/less/fauxton.less';
@@ -32,6 +33,7 @@ Fauxton.VersionInfo = Backbone.Model.extend({
});
FauxtonAPI.addReducers({
+ navigation: navigationReducers,
notifications: notificationsReducer
});
diff --git a/app/addons/fauxton/navigation/__tests__/login-logout-test.js
b/app/addons/fauxton/navigation/__tests__/login-logout-test.js
index 097e4952f..e84c2afd7 100644
--- a/app/addons/fauxton/navigation/__tests__/login-logout-test.js
+++ b/app/addons/fauxton/navigation/__tests__/login-logout-test.js
@@ -13,25 +13,23 @@
import React from 'react';
import { mount } from 'enzyme';
-
import NavBar from '../components/NavBar';
describe('Navigation Bar', () => {
-
+ const defaultProps = {
+ activeLink: '',
+ isMinimized: false,
+ version: '42',
+ navLinks: [],
+ bottomNavLinks: [],
+ footerNavLinks: [],
+ isNavBarVisible: true,
+ isLoginSectionVisible: true,
+ isLoginVisibleInsteadOfLogout: true,
+ toggleNavbarMenu: () => {}
+ };
it('renders with login button when logged out', () => {
- const props = {
- activeLink: '',
- isMinimized: false,
- version: '42',
- navLinks: [],
- bottomNavLinks: [],
- footerNavLinks: [],
- isNavBarVisible: true,
- isLoginSectionVisible: true,
- isLoginVisibleInsteadOfLogout: true
- };
-
- const navBar = mount(<NavBar {...props} />);
+ const navBar = mount(<NavBar {...defaultProps} />);
const button = navBar.find('[href="#/login"]');
expect(button.text()).toContain('Login');
@@ -39,19 +37,11 @@ describe('Navigation Bar', () => {
it('renders with logout button when logged in', () => {
const props = {
- activeLink: '',
- isMinimized: false,
- version: '42',
- navLinks: [],
- bottomNavLinks: [],
- footerNavLinks: [],
username: 'Rocko',
- isNavBarVisible: true,
- isLoginSectionVisible: true,
isLoginVisibleInsteadOfLogout: false
};
- const navBar = mount(<NavBar {...props} />);
+ const navBar = mount(<NavBar {...defaultProps} {...props} />);
const button = navBar.find('[href="#/logout"]');
expect(button.text()).toContain('Log Out');
@@ -59,19 +49,12 @@ describe('Navigation Bar', () => {
it('Admin Party has no Logout button and no Login button', () => {
const props = {
- activeLink: '',
- isMinimized: false,
- version: '42',
- navLinks: [],
- bottomNavLinks: [],
- footerNavLinks: [],
username: 'Rocko',
- isNavBarVisible: true,
isLoginSectionVisible: false,
isLoginVisibleInsteadOfLogout: false
};
- const navBar = mount(<NavBar {...props} />);
+ const navBar = mount(<NavBar {...defaultProps} {...props} />);
expect(navBar.text()).not.toMatch(/Login/);
expect(navBar.text()).not.toMatch(/Log Out/);
diff --git a/app/addons/fauxton/navigation/__tests__/navbar-test.js
b/app/addons/fauxton/navigation/__tests__/navbar-test.js
index 769b945b1..ba524839d 100644
--- a/app/addons/fauxton/navigation/__tests__/navbar-test.js
+++ b/app/addons/fauxton/navigation/__tests__/navbar-test.js
@@ -9,58 +9,60 @@
// 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 NavBarContainer from "../container/NavBar";
-import FauxtonAPI from "../../../../core/api";
-import ActionTypes from "../actiontypes";
-import React from "react";
-import ReactDOM from "react-dom";
+
import {mount} from 'enzyme';
+import React from 'react';
+import NavBar from '../components/NavBar';
describe('Navigation Bar', () => {
- FauxtonAPI.session = {
- user: () => {}
+ const defaultProps = {
+ isMinimized: true,
+ version: '',
+ username: '',
+ navLinks: [],
+ bottomNavLinks: [],
+ footerNavLinks: [],
+ isNavBarVisible: true,
+ isLoginSectionVisible: false,
+ isLoginVisibleInsteadOfLogout: true,
+ toggleNavbarMenu: () => {}
};
it('is displayed by default', () => {
- const navbar = mount(<NavBarContainer />);
+ const navbar = mount(<NavBar {...defaultProps}/>);
expect(navbar.find('.faux-navbar').length).toBe(1);
});
it('is dynamically displayed by isNavBarVisible', () => {
- const navbar = mount(<NavBarContainer />);
+ const navbar = mount(<NavBar
+ {...defaultProps}
+ isNavBarVisible={false}/>);
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_HIDE
- });
- navbar.update();
expect(navbar.find('.faux-navbar').length).toBe(0);
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_SHOW
- });
+ navbar.setProps({ isNavBarVisible: true });
navbar.update();
expect(navbar.find('.faux-navbar').length).toBe(1);
});
it('can display items with icon badge', () => {
- FauxtonAPI.dispatch({
- type: ActionTypes.ADD_NAVBAR_LINK,
- link: {
+ const navLinks = [
+ {
href: "#/_with_badge",
title: "WithBadge",
icon: "fonticon-database",
badge: true
- }
- });
- FauxtonAPI.dispatch({
- type: ActionTypes.ADD_NAVBAR_LINK,
- link: {
+ },
+ {
href: "#/_without_badge",
title: "WithoutBadge",
icon: "fonticon-database"
}
- });
- const navbar = mount(<NavBarContainer />);
+ ];
+
+ const navbar = mount(<NavBar
+ {...defaultProps}
+ navLinks={navLinks}/>);
expect(navbar.find('div[data-nav-name="WithoutBadge"]
i.faux-navbar__icon-badge').length, 0);
expect(navbar.find('div[data-nav-name="WithBadge"]
i.faux-navbar__icon-badge').length, 1);
});
diff --git a/app/addons/fauxton/navigation/__tests__/navigation-reducers.js
b/app/addons/fauxton/navigation/__tests__/navigation-reducers.js
new file mode 100644
index 000000000..f2f9f12b0
--- /dev/null
+++ b/app/addons/fauxton/navigation/__tests__/navigation-reducers.js
@@ -0,0 +1,185 @@
+// 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 ActionTypes from '../actiontypes';
+import reducer from '../reducers';
+
+describe('NavBar Reducer', () => {
+
+ describe('add links', () => {
+
+ it('to nav links', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'mylink'
+ }
+ };
+ const newState = reducer(undefined, action);
+ expect(newState.navLinks[0].id).toMatch(action.link.id);
+ });
+
+ it('to top nav links', () => {
+ const action1 = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: { id: 'mylink1' }
+ };
+ const action2 = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: { id: 'mylink2', top: true }
+ };
+ let newState = reducer(undefined, action1);
+ newState = reducer(newState, action2);
+
+ expect(newState.navLinks[0].id).toMatch(action2.link.id);
+ });
+
+ it('to bottom nav', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'bottomNav',
+ bottomNav: true
+ }
+ };
+ const newState = reducer(undefined, action);
+ expect(newState.bottomNavLinks[0].id).toMatch(action.link.id);
+ });
+
+ it('to top of bottom nav', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'bottomNav',
+ bottomNav: true,
+ top: true
+ }
+ };
+ const newState = reducer(undefined, action);
+ expect(newState.bottomNavLinks[0].id).toMatch(action.link.id);
+ });
+
+ it('to footer nav', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'footerNav',
+ footerNav: true
+ }
+ };
+ const newState = reducer(undefined, action);
+ expect(newState.footerNavLinks[0].id).toMatch(action.link.id);
+ });
+ });
+
+ describe('remove link', () => {
+ it('from nav links', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'remove_link'
+ }
+ };
+ let newState = reducer(undefined, action);
+ action.type = ActionTypes.REMOVE_NAVBAR_LINK;
+ newState = reducer(newState, action);
+
+ expect(newState.navLinks.length).toBe(0);
+ });
+
+ it('remove link from list only when it exists', () => {
+ const addAction = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'remove_link1',
+ footerNav: true
+ }
+ };
+ let newState = reducer(undefined, addAction);
+ addAction.link = { id: 'remove_link2', footerNav: true };
+ newState = reducer(newState, addAction);
+ addAction.link = { id: 'remove_link3', footerNav: true };
+ newState = reducer(newState, addAction);
+ expect(newState.footerNavLinks.length).toBe(3);
+
+ const removeAction = {
+ type: ActionTypes.REMOVE_NAVBAR_LINK,
+ link: addAction.link
+ };
+ newState = reducer(newState, removeAction);
+ newState = reducer(newState, removeAction);
+ newState = reducer(newState, removeAction);
+ expect(newState.footerNavLinks.length).toBe(2);
+ });
+
+ it('from bottom nav links', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'remove_link',
+ bottomNav: true
+ }
+ };
+ let newState = reducer(undefined, action);
+ action.type = ActionTypes.REMOVE_NAVBAR_LINK;
+ newState = reducer(newState, action);
+
+ expect(newState.bottomNavLinks.length).toBe(0);
+ });
+
+ it('from footer nav links', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'remove_link',
+ footerNav: true
+ }
+ };
+ let newState = reducer(undefined, action);
+ action.type = ActionTypes.REMOVE_NAVBAR_LINK;
+ newState = reducer(newState, action);
+
+ expect(newState.footerNavLinks.length).toBe(0);
+ });
+ });
+
+ describe('update link', () => {
+ it('for nav links', () => {
+ const action = {
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: {
+ id: 'update-link',
+ title: 'first'
+ }
+ };
+ let newState = reducer(undefined, action);
+ action.type = ActionTypes.UPDATE_NAVBAR_LINK;
+ action.link.title = 'second';
+ newState = reducer(newState, action);
+
+ expect(newState.navLinks[0].title).toMatch('second');
+ });
+
+ });
+
+ describe('set version', () => {
+ it('stores version number', () => {
+ const action = {
+ type: ActionTypes.NAVBAR_SET_VERSION_INFO,
+ version: 1234
+ };
+ const newState = reducer(undefined, action);
+ expect(newState.version).toBe(1234);
+ });
+
+ });
+});
diff --git a/app/addons/fauxton/navigation/__tests__/navigation-store-test.js
b/app/addons/fauxton/navigation/__tests__/navigation-store-test.js
deleted file mode 100644
index c664dceec..000000000
--- a/app/addons/fauxton/navigation/__tests__/navigation-store-test.js
+++ /dev/null
@@ -1,221 +0,0 @@
-// 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 FauxtonAPI from "../../../../core/api";
-import Stores from "../stores";
-const navBarStore = Stores.navBarStore;
-
-describe('NavBarStore', () => {
- beforeEach(() => {
- FauxtonAPI.dispatch({
- type: 'CLEAR_NAVBAR_LINK',
- });
-
- });
-
- describe('add links', () => {
-
- it('to nav links', () => {
- var link = {
- id: 'mylink'
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getNavLinks()[0].id).toMatch(link.id);
- });
-
- it('to top nav links', () => {
- var link1 = {
- id: 'mylink1'
- };
-
- var link2 = {
- id: 'mylink2',
- top: true
- };
-
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link1
- });
-
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link2
- });
-
- expect(navBarStore.getNavLinks()[0].id).toMatch(link2.id);
- });
-
- it('to bottom nav', () => {
- var link = {
- id: 'bottomNav',
- bottomNav: true
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getBottomNavLinks()[0].id).toMatch(link.id);
- });
-
- it('to top of bottom nav', () => {
- var link = {
- id: 'bottomNav',
- bottomNav: true,
- top: true
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getBottomNavLinks()[0].id).toMatch(link.id);
- });
-
- it('to footer nav', () => {
- var link = {
- id: 'footerNav',
- footerNav: true
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getFooterNavLinks()[0].id).toMatch(link.id);
- });
- });
-
- describe('remove link', () => {
- it('from nav links', () => {
- var link = {
- id: 'remove_link',
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- FauxtonAPI.dispatch({
- type: 'REMOVE_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getNavLinks().length).toBe(0);
- });
-
- it('remove link from list', () => {
- const addLink = (id) => {
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: {
- id: id,
- footerNav: true
- }
- });
- };
- const removeLink = () => {
- FauxtonAPI.dispatch({
- type: 'REMOVE_NAVBAR_LINK',
- link: {
- id: 'remove_link3',
- footerNav: true
- }
- });
- };
- addLink('remove_link1');
- addLink('remove_link2');
- addLink('remove_link3');
-
- removeLink();
- removeLink();
- removeLink();
-
- expect(navBarStore.getFooterNavLinks().length).toBe(2);
- });
-
- it('from bottom nav links', () => {
- var link = {
- id: 'remove_link',
- bottomNav: true
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- FauxtonAPI.dispatch({
- type: 'REMOVE_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getBottomNavLinks().length).toBe(0);
- });
-
- it('from footer nav links', () => {
- var link = {
- id: 'remove_link',
- footerNav: true
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- FauxtonAPI.dispatch({
- type: 'REMOVE_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getFooterNavLinks().length).toBe(0);
- });
- });
-
- describe('update link', () => {
- it('for nav links', () => {
- var link = {
- id: 'update-link',
- title: 'first'
- };
- FauxtonAPI.dispatch({
- type: 'ADD_NAVBAR_LINK',
- link: link
- });
-
- link.title = 'second';
-
- FauxtonAPI.dispatch({
- type: 'UPDATE_NAVBAR_LINK',
- link: link
- });
-
- expect(navBarStore.getNavLinks()[0].title).toMatch('second');
- });
-
- });
-
- describe('set version', () => {
- it('stores version number', () => {
- FauxtonAPI.dispatch({
- type: 'NAVBAR_SET_VERSION_INFO',
- version: 1234
- });
-
- expect(navBarStore.getVersion()).toBe(1234);
- });
-
- });
-});
diff --git a/app/addons/fauxton/navigation/actions.js
b/app/addons/fauxton/navigation/actions.js
index 354815706..ac26091f3 100644
--- a/app/addons/fauxton/navigation/actions.js
+++ b/app/addons/fauxton/navigation/actions.js
@@ -10,53 +10,51 @@
// License for the specific language governing permissions and limitations
under
// the License.
-import FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-
-export default {
- toggleNavbarMenu () {
- FauxtonAPI.dispatch({
- type: ActionTypes.TOGGLE_NAVBAR_MENU
- });
- },
-
- addHeaderLink (link) {
- FauxtonAPI.dispatch({
- type: ActionTypes.ADD_NAVBAR_LINK,
- link: link
- });
- },
-
- removeHeaderLink (link) {
- FauxtonAPI.dispatch({
- type: ActionTypes.REMOVE_NAVBAR_LINK,
- link: link
- });
- },
-
- setNavbarVersionInfo (versionInfo) {
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_SET_VERSION_INFO,
- version: versionInfo
- });
- },
-
- setNavbarActiveLink (header) {
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_ACTIVE_LINK,
- name: header
- });
- },
-
- showNavBar () {
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_SHOW
- });
- },
-
- hideNavBar () {
- FauxtonAPI.dispatch({
- type: ActionTypes.NAVBAR_HIDE
- });
- }
+import FauxtonAPI from '../../../core/api';
+import ActionTypes from './actiontypes';
+
+export const toggleNavbarMenu = () => (dispatch) => {
+ dispatch({
+ type: ActionTypes.TOGGLE_NAVBAR_MENU
+ });
+};
+
+export const addHeaderLink = (link) => (dispatch) => {
+ dispatch({
+ type: ActionTypes.ADD_NAVBAR_LINK,
+ link: link
+ });
+};
+
+export const removeHeaderLink = (link) => (dispatch) => {
+ dispatch({
+ type: ActionTypes.REMOVE_NAVBAR_LINK,
+ link: link
+ });
+};
+
+export const setNavbarVersionInfo = (versionInfo) => {
+ FauxtonAPI.reduxDispatch({
+ type: ActionTypes.NAVBAR_SET_VERSION_INFO,
+ version: versionInfo
+ });
+};
+
+export const setNavbarActiveLink = (header) => (dispatch) => {
+ dispatch({
+ type: ActionTypes.NAVBAR_ACTIVE_LINK,
+ name: header
+ });
+};
+
+export const showNavBar = () => (dispatch) => {
+ dispatch({
+ type: ActionTypes.NAVBAR_SHOW
+ });
+};
+
+export const hideNavBar = () => (dispatch) => {
+ dispatch({
+ type: ActionTypes.NAVBAR_HIDE
+ });
};
diff --git a/app/addons/fauxton/navigation/actiontypes.js
b/app/addons/fauxton/navigation/actiontypes.js
index 2a5d72f36..e00706272 100644
--- a/app/addons/fauxton/navigation/actiontypes.js
+++ b/app/addons/fauxton/navigation/actiontypes.js
@@ -14,7 +14,6 @@ export default {
ADD_NAVBAR_LINK: 'ADD_NAVBAR_LINK',
TOGGLE_NAVBAR_MENU: 'TOGGLE_NAVBAR_MENU',
UPDATE_NAVBAR_LINK: 'UPDATE_NAVBAR_LINK',
- CLEAR_NAVBAR_LINK: 'CLEAR_NAVBAR_LINK',
REMOVE_NAVBAR_LINK: 'REMOVE_NAVBAR_LINK',
HIDE_NAVBAR_LINK_BADGE: 'HIDE_NAVBAR_LINK_BADGE',
SHOW_NAVBAR_LINK_BADGE: 'SHOW_NAVBAR_LINK_BADGE',
diff --git a/app/addons/fauxton/navigation/components/NavBar.js
b/app/addons/fauxton/navigation/components/NavBar.js
index 77cb3abe1..89d0c486c 100644
--- a/app/addons/fauxton/navigation/components/NavBar.js
+++ b/app/addons/fauxton/navigation/components/NavBar.js
@@ -10,10 +10,9 @@
// License for the specific language governing permissions and limitations
under
// the License.
+import classNames from 'classnames';
import PropTypes from 'prop-types';
-
import React, { Component } from 'react';
-
import Footer from './Footer';
import Burger from './Burger';
import NavLink from './NavLink';
@@ -21,12 +20,12 @@ import Brand from './Brand';
import LogoutButton from './LogoutButton';
import LoginButton from './LoginButton';
-import Actions from "../actions";
-
-import classNames from 'classnames';
-
class NavBar extends Component {
+ constructor(props) {
+ super(props);
+ }
+
createLinks (links) {
const { activeLink, isMinimized } = this.props;
@@ -39,10 +38,6 @@ class NavBar extends Component {
});
}
- toggleMenu () {
- Actions.toggleNavbarMenu();
- }
-
render () {
const {
isMinimized,
@@ -51,7 +46,8 @@ class NavBar extends Component {
isLoginVisibleInsteadOfLogout,
activeLink,
username,
- isNavBarVisible
+ isNavBarVisible,
+ toggleNavbarMenu
} = this.props;
if (!isNavBarVisible) {
@@ -76,7 +72,7 @@ class NavBar extends Component {
<div className={navClasses}>
<nav>
<div className="faux-navbar__linkcontainer">
- <Burger isMinimized={isMinimized} toggleMenu={this.toggleMenu}/>
+ <Burger isMinimized={isMinimized} toggleMenu={toggleNavbarMenu}/>
<div className="faux-navbar__links">
{navLinks}
{bottomNavLinks}
@@ -110,7 +106,8 @@ NavBar.propTypes = {
footerNavLinks: PropTypes.array,
isNavBarVisible: PropTypes.bool,
isLoginSectionVisible: PropTypes.bool.isRequired,
- isLoginVisibleInsteadOfLogout: PropTypes.bool.isRequired
+ isLoginVisibleInsteadOfLogout: PropTypes.bool.isRequired,
+ toggleNavbarMenu: PropTypes.func.isRequired
};
export default NavBar;
diff --git a/app/addons/fauxton/navigation/container/NavBar.js
b/app/addons/fauxton/navigation/container/NavBar.js
index d5efb135b..2703b7969 100644
--- a/app/addons/fauxton/navigation/container/NavBar.js
+++ b/app/addons/fauxton/navigation/container/NavBar.js
@@ -10,55 +10,38 @@
// License for the specific language governing permissions and limitations
under
// the License.
-import FauxtonAPI from "../../../../core/api";
-import React from "react";
-
-import ReactDOM from "react-dom";
-import Stores from "../stores";
-
+import { connect } from 'react-redux';
+import FauxtonAPI from '../../../../core/api';
import NavBar from '../components/NavBar';
-
-const navBarStore = Stores.navBarStore;
-
-class NavBarContainer extends React.Component {
- getStoreState = () => {
- return {
- navLinks: navBarStore.getNavLinks(),
- bottomNavLinks: navBarStore.getBottomNavLinks(),
- footerNavLinks: navBarStore.getFooterNavLinks(),
- activeLink: navBarStore.getActiveLink(),
- version: navBarStore.getVersion(),
- isMinimized: navBarStore.isMinimized(),
- isNavBarVisible: navBarStore.isNavBarVisible(),
-
- isLoginSectionVisible: navBarStore.getIsLoginSectionVisible(),
- isLoginVisibleInsteadOfLogout:
navBarStore.getIsLoginVisibleInsteadOfLogout()
- };
+import * as Actions from '../actions';
+
+const mapStateToProps = ({ navigation }) => {
+ const user = FauxtonAPI.session.user();
+ return {
+ navLinks: navigation.navLinks,
+ bottomNavLinks: navigation.bottomNavLinks,
+ footerNavLinks: navigation.footerNavLinks,
+ activeLink: navigation.activeLink,
+ version: navigation.version,
+ isMinimized: navigation.isMinimized,
+ isNavBarVisible: navigation.navBarVisible,
+ isLoginSectionVisible: navigation.loginSectionVisible,
+ isLoginVisibleInsteadOfLogout: navigation.loginVisibleInsteadOfLogout,
+ username: (user && user.name) ? user.name : ''
};
+};
- onChange = () => {
- this.setState(this.getStoreState());
+const mapDispatchToProps = (dispatch) => {
+ return {
+ toggleNavbarMenu: () => {
+ dispatch(Actions.toggleNavbarMenu());
+ }
};
+};
- state = this.getStoreState();
-
- componentDidMount() {
- navBarStore.on('change', this.onChange, this);
- }
-
- componentWillUnmount() {
- navBarStore.off('change', this.onChange);
- }
-
- render() {
- const user = FauxtonAPI.session.user();
-
- const username = (user && user.name) ? user.name : '';
- return (
- <NavBar {...this.state} username={username} />
- );
- }
-}
-
+const NavBarContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(NavBar);
export default NavBarContainer;
diff --git a/app/addons/fauxton/navigation/reducers.js
b/app/addons/fauxton/navigation/reducers.js
new file mode 100644
index 000000000..6af5d2cba
--- /dev/null
+++ b/app/addons/fauxton/navigation/reducers.js
@@ -0,0 +1,209 @@
+// 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 ActionTypes from './actiontypes';
+
+const initialState = {
+ isMinimized: true,
+ activeLink: null,
+ version: null,
+ navLinks: [],
+ footerNavLinks: [],
+ bottomNavLinks: [],
+ navBarVisible: true,
+ loginSectionVisible: false,
+ loginVisibleInsteadOfLogout: true
+};
+
+function addLink(state, link) {
+ const newState = { ...state };
+
+ if (link.top && !link.bottomNav) {
+ newState.navLinks = [].concat(newState.navLinks);
+ newState.navLinks.unshift(link);
+ return newState;
+ }
+ if (link.top && link.bottomNav) {
+ newState.bottomNavLinks = [].concat(newState.bottomNavLinks);
+ newState.bottomNavLinks.unshift(link);
+ return newState;
+ }
+ if (link.bottomNav) {
+ newState.bottomNavLinks = [].concat(newState.bottomNavLinks);
+ newState.bottomNavLinks.push(link);
+ return newState;
+ }
+ if (link.footerNav) {
+ newState.footerNavLinks = [].concat(newState.footerNavLinks);
+ newState.footerNavLinks.push(link);
+ return newState;
+ }
+
+ newState.navLinks = [].concat(newState.navLinks);
+ newState.navLinks.push(link);
+ return newState;
+}
+
+function removeLink (state, removeLink) {
+ const {links, sectionName} = getLinkSection(state, removeLink);
+
+ // create new array without the link to remove
+ const newLinks = links.filter(link => link.id !== removeLink.id);
+
+ if (newLinks.length === links.length) {
+ return state;
+ }
+
+ const newState = { ...state };
+ newState[sectionName] = newLinks;
+ return newState;
+}
+
+function updateLink (state, link) {
+ const {links, sectionName} = getLinkSection(state, link);
+
+ // create new array and updates the link when found
+ let found = false;
+ const newLinks = links.map(el => {
+ if (el.id === link.id) {
+ found = true;
+ return {
+ ...el,
+ title: link.title,
+ href: link.href
+ };
+ }
+ return el;
+ });
+
+ if (!found) {
+ return state;
+ }
+
+ const newState = { ...state };
+ newState[sectionName] = newLinks;
+ return newState;
+}
+
+function setLinkBadgeVisible (state, link, visible) {
+ const {links, sectionName} = getLinkSection(state, link);
+
+ let found = false;
+ const newLinks = links.map(el => {
+ if (el.title === link.title) {
+ found = true;
+ return {
+ ...el,
+ badge: visible
+ };
+ }
+ return el;
+ });
+
+ if (!found) {
+ return state;
+ }
+
+ const newState = { ...state };
+ newState[sectionName] = newLinks;
+ return newState;
+}
+
+function getLinkSection (state, link) {
+ let links = state.navLinks;
+ let sectionName = 'navLinks';
+
+ if (link.bottomNav) {
+ links = state.bottomNavLinks;
+ sectionName = 'bottomNavLinks';
+ }
+
+ if (link.footerNav) {
+ links = state.footerNavLinks;
+ sectionName = 'footerNavLinks';
+ }
+
+ return { links, sectionName };
+}
+
+export default function navigation(state = initialState, action) {
+ switch (action.type) {
+
+ case ActionTypes.ADD_NAVBAR_LINK:
+ return addLink(state, action.link);
+
+ case ActionTypes.TOGGLE_NAVBAR_MENU:
+ return {
+ ...state,
+ isMinimized: !state.isMinimized
+ };
+
+ case ActionTypes.UPDATE_NAVBAR_LINK:
+ return updateLink(state, action.link);
+
+ case ActionTypes.REMOVE_NAVBAR_LINK:
+ return removeLink(state, action.link);
+
+ case ActionTypes.SHOW_NAVBAR_LINK_BADGE:
+ return setLinkBadgeVisible(state, action.link, true);
+
+ case ActionTypes.HIDE_NAVBAR_LINK_BADGE:
+ return setLinkBadgeVisible(state, action.link, false);
+
+ case ActionTypes.NAVBAR_SET_VERSION_INFO:
+ return {
+ ...state,
+ version: action.version
+ };
+
+ case ActionTypes.NAVBAR_ACTIVE_LINK:
+ return {
+ ...state,
+ activeLink: action.name
+ };
+
+ case ActionTypes.NAVBAR_HIDE:
+ return {
+ ...state,
+ navBarVisible: false
+ };
+
+ case ActionTypes.NAVBAR_SHOW:
+ return {
+ ...state,
+ navBarVisible: true
+ };
+
+ case ActionTypes.NAVBAR_SHOW_HIDE_LOGIN_LOGOUT_SECTION:
+ return {
+ ...state,
+ loginSectionVisible: action.visible
+ };
+
+ case ActionTypes.NAVBAR_SHOW_LOGIN_BUTTON:
+ return {
+ ...state,
+ loginSectionVisible: true,
+ loginVisibleInsteadOfLogout: true
+ };
+
+ case ActionTypes.NAVBAR_SHOW_LOGOUT_BUTTON:
+ return {
+ ...state,
+ loginSectionVisible: true,
+ loginVisibleInsteadOfLogout: false
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/app/addons/fauxton/navigation/stores.js
b/app/addons/fauxton/navigation/stores.js
deleted file mode 100644
index d08f24339..000000000
--- a/app/addons/fauxton/navigation/stores.js
+++ /dev/null
@@ -1,251 +0,0 @@
-// 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 FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-import {findIndex} from 'lodash';
-
-const Stores = {};
-
-Stores.NavBarStore = FauxtonAPI.Store.extend({
- initialize () {
- this.reset();
- },
-
- reset () {
- this._isMinimized = true;
- this._activeLink = null;
- this._version = null;
- this._navLinks = [];
- this._footerNavLinks = [];
- this._bottomNavLinks = [];
- this._navBarVisible = true;
-
- this._loginSectionVisible = false;
- this._loginVisibleInsteadOfLogout = true;
- },
-
- getIsLoginSectionVisible () {
- return this._loginSectionVisible;
- },
-
- getIsLoginVisibleInsteadOfLogout () {
- return this._loginVisibleInsteadOfLogout;
- },
-
- isNavBarVisible () {
- return this._navBarVisible;
- },
-
- showNavBar () {
- this._navBarVisible = true;
- },
-
- hideNavBar () {
- this._navBarVisible = false;
- },
-
- addLink (link) {
- if (link.top && !link.bottomNav) {
- this._navLinks.unshift(link);
- return;
- }
- if (link.top && link.bottomNav) {
- this._bottomNavLinks.unshift(link);
- return;
- }
- if (link.bottomNav) {
- this._bottomNavLinks.push(link);
- return;
- }
- if (link.footerNav) {
- this._footerNavLinks.push(link);
- return;
- }
-
- this._navLinks.push(link);
- },
-
- removeLink (removeLink) {
- const links = this.getLinkSection(removeLink);
-
- const indexOf = findIndex(links, link => {
- if (link.id === removeLink.id) {
- return true;
- }
-
- return false;
- });
-
- if (indexOf === -1) { return; }
-
- links.splice(indexOf, 1);
- },
-
- getNavLinks () {
- return this._navLinks;
- },
-
- getBottomNavLinks () {
- return this._bottomNavLinks;
- },
-
- getFooterNavLinks () {
- return this._footerNavLinks;
- },
-
- toggleMenu () {
- this._isMinimized = !this._isMinimized;
- },
-
- getLinkSection (link) {
- let links = this._navLinks;
-
- if (link.bottomNav) {
- links = this._bottomNavLinks;
- }
-
- if (link.footerNav) {
- links = this._footerNavLinks;
- }
-
- return links;
- },
-
- updateLink (link) {
- let oldLink;
- const links = this.getLinkSection(link);
-
- oldLink = _.find(links, function (oldLink) {
- return oldLink.id === link.id;
- });
-
- if (!oldLink) { return; }
-
- oldLink.title = link.title;
- oldLink.href = link.href;
- },
-
- showLinkBadge (link) {
- const links = this.getLinkSection(link);
- const selectedLink = links.find(function (oldLink) {
- return oldLink.title === link.title;
- });
- if (selectedLink) {
- selectedLink.badge = true;
- }
- },
-
- hideLinkBadge (link) {
- const links = this.getLinkSection(link);
- const selectedLink = links.find(function (oldLink) {
- return oldLink.title === link.title;
- });
-
- if (selectedLink) {
- selectedLink.badge = false;
- }
- },
-
- getVersion () {
- return this._version;
- },
-
- setVersion (version) {
- this._version = version;
- },
-
- getActiveLink () {
- return this._activeLink;
- },
-
- setActiveLink (activeLink) {
- this._activeLink = activeLink;
- },
-
- isMinimized () {
- return this._isMinimized;
- },
-
- dispatch (action) {
- switch (action.type) {
- case ActionTypes.ADD_NAVBAR_LINK:
- this.addLink(action.link);
- break;
-
- case ActionTypes.TOGGLE_NAVBAR_MENU:
- this.toggleMenu();
- break;
-
- case ActionTypes.UPDATE_NAVBAR_LINK:
- this.updateLink(action.link);
- break;
-
- case ActionTypes.CLEAR_NAVBAR_LINK:
- this.reset();
- break;
-
- case ActionTypes.REMOVE_NAVBAR_LINK:
- this.removeLink(action.link);
- break;
-
- case ActionTypes.SHOW_NAVBAR_LINK_BADGE:
- this.showLinkBadge(action.link);
- break;
-
- case ActionTypes.HIDE_NAVBAR_LINK_BADGE:
- this.hideLinkBadge(action.link);
- break;
-
- case ActionTypes.NAVBAR_SET_VERSION_INFO:
- this.setVersion(action.version);
- break;
-
- case ActionTypes.NAVBAR_ACTIVE_LINK:
- this.setActiveLink(action.name);
- break;
-
- case ActionTypes.NAVBAR_HIDE:
- this.hideNavBar();
- break;
-
- case ActionTypes.NAVBAR_SHOW:
- this.showNavBar();
- break;
-
- case ActionTypes.NAVBAR_SHOW_HIDE_LOGIN_LOGOUT_SECTION:
- this._loginSectionVisible = action.visible;
- break;
-
- case ActionTypes.NAVBAR_SHOW_LOGIN_BUTTON:
- this._loginSectionVisible = true;
- this._loginVisibleInsteadOfLogout = true;
- break;
-
- case ActionTypes.NAVBAR_SHOW_LOGOUT_BUTTON:
- this._loginSectionVisible = true;
- this._loginVisibleInsteadOfLogout = false;
- break;
-
- default:
- return;
- // do nothing
- }
-
- this.triggerChange();
- }
-});
-
-Stores.navBarStore = new Stores.NavBarStore();
-Stores.navBarStore.dispatchToken =
FauxtonAPI.dispatcher.register(Stores.navBarStore.dispatch.bind(Stores.navBarStore));
-
-export default Stores;
diff --git a/app/app.js b/app/app.js
index 6c3916040..ed6d99488 100644
--- a/app/app.js
+++ b/app/app.js
@@ -38,41 +38,41 @@ FauxtonAPI.config({
// I haven't wrapped these dispatch methods in a action
// because I don't want to require fauxton/actions in this method.
addHeaderLink: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'ADD_NAVBAR_LINK',
link: link
});
},
updateHeaderLink: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'UPDATE_NAVBAR_LINK',
link: link
});
},
removeHeaderLink: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'REMOVE_NAVBAR_LINK',
link: link
});
},
hideLogin: function () {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'NAVBAR_SHOW_HIDE_LOGIN_LOGOUT_SECTION',
visible: false
});
},
showLogout: function () {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'NAVBAR_SHOW_LOGOUT_BUTTON'
});
},
showLogin: function () {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'NAVBAR_SHOW_LOGIN_BUTTON'
});
}
diff --git a/app/core/base.js b/app/core/base.js
index 0762f7acc..2278d84ff 100644
--- a/app/core/base.js
+++ b/app/core/base.js
@@ -24,19 +24,19 @@ var FauxtonAPI = {
// I haven't wrapped these dispatch methods in a action
// because I don't want to require fauxton/actions in this method.
addHeaderLink: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'ADD_NAVBAR_LINK',
link: link
});
},
showHeaderLinkBadge: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'SHOW_NAVBAR_LINK_BADGE',
link: link
});
},
hideHeaderLinkBadge: function (link) {
- FauxtonAPI.dispatch({
+ FauxtonAPI.reduxDispatch({
type: 'HIDE_NAVBAR_LINK_BADGE',
link: link
});
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services