diff --git a/resources/frontend_client/app/card/actions.js b/resources/frontend_client/app/card/actions.js new file mode 100644 index 0000000000000000000000000000000000000000..7e7ec53b9426417e17e20090893af474f690b7c8 --- /dev/null +++ b/resources/frontend_client/app/card/actions.js @@ -0,0 +1,103 @@ +"use strict"; + +import { createAction } from "redux-actions"; +import moment from "moment"; + + +// HACK: just use our Angular resources for now +function AngularResourceProxy(serviceName, methods) { + methods.forEach((methodName) => { + this[methodName] = function(...args) { + let service = angular.element(document.querySelector("body")).injector().get(serviceName); + return service[methodName](...args).$promise; + } + }); +} + +// similar to createAction but accepts a (redux-thunk style) thunk and dispatches based on whether +// the promise returned from the thunk resolves or rejects, similar to redux-promise +function createThunkAction(actionType, actionThunkCreator) { + return function(...actionArgs) { + var thunk = actionThunkCreator(...actionArgs); + return async function(dispatch, getState) { + try { + let payload = await thunk(dispatch, getState); + dispatch({ type: actionType, payload }); + } catch (error) { + dispatch({ type: actionType, payload: error, error: true }); + throw error; + } + } + } +} + +// resource wrappers +const CardApi = new AngularResourceProxy("Card", ["list"]); +const MetadataApi = new AngularResourceProxy("Metabase", ["db_list", "db_metadata"]); + + +// action constants +export const SET_CARDS_FILTER = 'SET_CARDS_FILTER'; +export const FETCH_CARDS = 'FETCH_CARDS'; +export const FETCH_DATABASES = 'FETCH_DATABASES'; +export const CLEAR_DATABASE_METADATA = 'CLEAR_DATABASE_METADATA'; +export const FETCH_DATABASE_METADATA = 'FETCH_DATABASE_METADATA'; + + +// action creators + +export const setCardsFilter = createThunkAction(SET_CARDS_FILTER, function(filterDef) { + return function(dispatch, getState) { + let { cardsFilter } = getState(); + let { database, table } = filterDef; + + if (database && !table && database !== cardsFilter.database) { + // user has picked a database different from any previous choice + dispatch(clearDatabaseMetadata()); + dispatch(fetchDatabaseMetadata(database)); + dispatch(fetchCards('database', database)); + + } else if (database && !table && database === cardsFilter.database) { + // user is simply clearing the table selection + dispatch(fetchCards('database', database)); + + } else if (database && table) { + // user has chosen a specific table to filter on + dispatch(fetchCards('table', table)); + + } else if (!database && cardsFilter.database) { + // clearing out all filters + dispatch(fetchCards('all')); + } + + return filterDef; + }; +}); + + +export const fetchCards = createThunkAction(FETCH_CARDS, function(filterMode, filterModelId) { + return async function(dispatch, getState) { + let cards = await CardApi.list({'filterMode' : filterMode, 'model_id' : filterModelId }); + for (var c of cards) { + c.created_at = moment(c.created_at); + c.updated_at = moment(c.updated_at); + c.icon = c.display ? 'illustration_visualization_' + c.display : null; + } + return cards; + }; +}); + +export const fetchDatabases = createThunkAction(FETCH_DATABASES, function() { + return async function(dispatch, getState) { + return await MetadataApi.db_list(); + }; +}); + + +export const clearDatabaseMetadata = createAction(CLEAR_DATABASE_METADATA); + +export const fetchDatabaseMetadata = createThunkAction(FETCH_DATABASE_METADATA, function(database_id) { + return async function(dispatch, getState) { + return await MetadataApi.db_metadata({'dbId': database_id}); + }; +}); diff --git a/resources/frontend_client/app/card/card.controllers.js b/resources/frontend_client/app/card/card.controllers.js index 9f009b16bc85c698a46cd69c3cc4d9a602b0a789..c6ac6fc3c2c190d3d3b1aef08f899f2ff4baccdf 100644 --- a/resources/frontend_client/app/card/card.controllers.js +++ b/resources/frontend_client/app/card/card.controllers.js @@ -1,5 +1,8 @@ 'use strict'; +import { createStore, applyMiddleware, combineReducers, compose } from 'redux'; +import promiseMiddleware from 'redux-promise'; +import thunkMidleware from "redux-thunk"; import _ from "underscore"; import MetabaseAnalytics from '../lib/analytics'; @@ -15,62 +18,31 @@ import QueryVisualization from '../query_builder/QueryVisualization.react'; import Query from "metabase/lib/query"; import { serializeCardForUrl, deserializeCardFromUrl, cleanCopyCard, urlForCardState } from './card.util'; -// Card Controllers -var CardControllers = angular.module('metabase.card.controllers', []); - -CardControllers.controller('CardList', ['$scope', '$location', 'Card', function($scope, $location, Card) { +import SavedQuestionsApp from './containers/SavedQuestionsApp.react'; +import * as reducers from './reducers'; - // $scope.cards: the list of cards being displayed +const finalCreateStore = compose( + applyMiddleware( + thunkMidleware, + promiseMiddleware + ), + createStore +); - $scope.deleteCard = function(cardId) { - Card.delete({ - 'cardId': cardId - }, function(result) { - $scope.cards = _.filter($scope.cards, function(card) { - return card.id != cardId; - }); - $scope.searchFilter = undefined; - }); - }; +const reducer = combineReducers(reducers); - $scope.unfavorite = function(unfavIdx) { - var cardToUnfav = $scope.cards[unfavIdx]; - Card.unfavorite({ - 'cardId': cardToUnfav.id - }, function(result) { - $scope.cards.splice(unfavIdx, 1); - }); - }; - - $scope.filter = function(filterMode) { - $scope.filterMode = filterMode; - - Card.list({ - 'filterMode': filterMode - }, function(cards) { - $scope.cards = cards; - }, function(error) { - console.log('error getting cards list', error); - }); - }; +// Card Controllers +var CardControllers = angular.module('metabase.card.controllers', []); - $scope.inlineSave = function(card, idx) { - Card.update(card, function(result) { - if (result && !result.error) { - $scope.cards[idx] = result; - } else { - return "error"; - } - }); +CardControllers.controller('CardList', ['$scope', '$location', function($scope, $location) { + $scope.Component = SavedQuestionsApp; + $scope.props = { + user: $scope.user, + onChangeLocation: function(url) { + $scope.$apply(() => $location.url(url)); + } }; - - // determine the appropriate filter to start with - if ($scope.hash && $scope.hash === 'fav') { - $scope.filter('fav'); - } else { - $scope.filter('all'); - } - + $scope.store = finalCreateStore(reducer, {}); }]); CardControllers.controller('CardDetail', [ diff --git a/resources/frontend_client/app/card/card.module.js b/resources/frontend_client/app/card/card.module.js index 4859347e78af86867772399821af87b853ebc045..ca70b8b6d096e546deffcf11ac634c578aa02ee5 100644 --- a/resources/frontend_client/app/card/card.module.js +++ b/resources/frontend_client/app/card/card.module.js @@ -29,4 +29,14 @@ Card.config(['$routeProvider', function($routeProvider) { templateUrl: '/app/card/partials/card_detail.html', controller: 'CardDetail' }); + + $routeProvider.when('/card/', { + template: '<div mb-redux-component class="flex flex-column flex-full" />', + controller: 'CardList', + resolve: { + appState: ["AppState", function(AppState) { + return AppState.init(); + }] + } + }); }]); diff --git a/resources/frontend_client/app/home/components/AccordianItem.react.js b/resources/frontend_client/app/card/components/AccordianItem.react.js similarity index 100% rename from resources/frontend_client/app/home/components/AccordianItem.react.js rename to resources/frontend_client/app/card/components/AccordianItem.react.js diff --git a/resources/frontend_client/app/home/components/CardFilters.react.js b/resources/frontend_client/app/card/components/CardFilters.react.js similarity index 100% rename from resources/frontend_client/app/home/components/CardFilters.react.js rename to resources/frontend_client/app/card/components/CardFilters.react.js diff --git a/resources/frontend_client/app/home/components/Cards.react.js b/resources/frontend_client/app/card/components/Cards.react.js similarity index 100% rename from resources/frontend_client/app/home/components/Cards.react.js rename to resources/frontend_client/app/card/components/Cards.react.js diff --git a/resources/frontend_client/app/card/components/SavedQuestions.react.js b/resources/frontend_client/app/card/components/SavedQuestions.react.js new file mode 100644 index 0000000000000000000000000000000000000000..3bcc74c356fde2ad9d4b75e3d8a5883752a295be --- /dev/null +++ b/resources/frontend_client/app/card/components/SavedQuestions.react.js @@ -0,0 +1,31 @@ +"use strict"; + +import React, { Component, PropTypes } from "react"; + +import Cards from "./Cards.react"; +import CardFilters from "./CardFilters.react"; + + +export default class SavedQuestions extends Component { + + render() { + return ( + <div className="flex flex-column flex-full"> + <div className="relative felx flex-column flex-full md-pl4"> + <div className="HomeLayout"> + <div className="HomeLayout-mainColumn"> + <Cards {...this.props} /> + </div> + </div> + <div className="HomeLayout-sidebar"> + <CardFilters {...this.props} /> + </div> + </div> + </div> + ); + } +} + +SavedQuestions.propTypes = { + dispatch: PropTypes.func.isRequired +}; diff --git a/resources/frontend_client/app/home/components/TableListing.react.js b/resources/frontend_client/app/card/components/TableListing.react.js similarity index 100% rename from resources/frontend_client/app/home/components/TableListing.react.js rename to resources/frontend_client/app/card/components/TableListing.react.js diff --git a/resources/frontend_client/app/card/containers/SavedQuestionsApp.react.js b/resources/frontend_client/app/card/containers/SavedQuestionsApp.react.js new file mode 100644 index 0000000000000000000000000000000000000000..d88c9d73e1f2c5353f0529edde19995491ff150a --- /dev/null +++ b/resources/frontend_client/app/card/containers/SavedQuestionsApp.react.js @@ -0,0 +1,14 @@ +"use strict"; + +import React, { Component, PropTypes } from "react"; +import { connect } from "react-redux"; + +import SavedQuestions from "../components/SavedQuestions.react"; +import { savedQuestionsSelectors } from "../selectors"; + +@connect(savedQuestionsSelectors) +export default class SavedQuestionsApp extends Component { + render() { + return <SavedQuestions {...this.props} />; + } +} diff --git a/resources/frontend_client/app/card/reducers.js b/resources/frontend_client/app/card/reducers.js new file mode 100644 index 0000000000000000000000000000000000000000..9c6c45c1ef7ee21750872640ff729cdc2b459dcb --- /dev/null +++ b/resources/frontend_client/app/card/reducers.js @@ -0,0 +1,33 @@ +"use strict"; + +import { handleActions } from 'redux-actions'; + +import { + SET_CARDS_FILTER, + FETCH_CARDS, + FETCH_DATABASES, + CLEAR_DATABASE_METADATA, + FETCH_DATABASE_METADATA +} from './actions'; + + +export const cardsFilter = handleActions({ + [SET_CARDS_FILTER]: { next: (state, { payload }) => payload } +}, {database: null, table: null}); + + +export const cards = handleActions({ + [FETCH_CARDS]: { next: (state, { payload }) => payload } +}, null); + + +export const databases = handleActions({ + [FETCH_DATABASES]: { next: (state, { payload }) => payload } +}, []); + + +export const databaseMetadata = handleActions({ + [FETCH_DATABASE_METADATA]: { next: (state, { payload }) => payload }, + [CLEAR_DATABASE_METADATA]: { next: (state, { payload }) => null } +}, null); + diff --git a/resources/frontend_client/app/card/selectors.js b/resources/frontend_client/app/card/selectors.js new file mode 100644 index 0000000000000000000000000000000000000000..176041c465bd96894225407e766792e5f4fca057 --- /dev/null +++ b/resources/frontend_client/app/card/selectors.js @@ -0,0 +1,14 @@ +"use strict"; + +import { createSelector } from 'reselect'; + + +// our master selector which combines all of our partial selectors above +export const savedQuestionsSelectors = createSelector( + [state => state.cardsFilter, + state => state.cards, + state => state.databases, + state => state.databaseMetadata], + + (cardsFilter, cards, databases, databaseMetadata) => ({cardsFilter, cards, databases, databaseMetadata}) +); \ No newline at end of file diff --git a/resources/frontend_client/app/components/Navbar.react.js b/resources/frontend_client/app/components/Navbar.react.js index 1785310f51fea1133fbd6689d357e09bf294a54c..aa0baba8cf4eaa0e37cb89cca490d6791e4d03f6 100644 --- a/resources/frontend_client/app/components/Navbar.react.js +++ b/resources/frontend_client/app/components/Navbar.react.js @@ -89,8 +89,13 @@ export default class Navbar extends Component { <li> <DashboardsDropdown {...this.props}></DashboardsDropdown> </li> - <li className="flex-align-right"> + <li> + <a className="NavItem cursor-pointer text-white no-decoration flex align-center p2" href="/card/">Saved Questions</a> + </li> + <li className="ml2"> <a className="rounded inline-block bg-white text-brand cursor-pointer p2 no-decoration" href="/q">New <span className="hide sm-show">Question</span></a> + </li> + <li className="flex-align-right"> <div className="inline-block text-white"><ProfileLink {...this.props}></ProfileLink></div> </li> </ul> diff --git a/resources/frontend_client/app/home/actions.js b/resources/frontend_client/app/home/actions.js index 05ccf503a20a37d94a32200ae929a7addac78d00..624ac2d7bd4dc7081e2afc47fd3417cbe5d4170d 100644 --- a/resources/frontend_client/app/home/actions.js +++ b/resources/frontend_client/app/home/actions.js @@ -1,7 +1,6 @@ "use strict"; import _ from "underscore"; -import { createAction } from "redux-actions"; import moment from "moment"; @@ -34,51 +33,14 @@ function createThunkAction(actionType, actionThunkCreator) { // resource wrappers const ActivityApi = new AngularResourceProxy("Activity", ["list", "recent_views"]); -const CardApi = new AngularResourceProxy("Card", ["list"]); -const MetadataApi = new AngularResourceProxy("Metabase", ["db_list", "db_metadata"]); // action constants -export const SET_SELECTED_TAB = 'SET_SELECTED_TAB'; -export const SET_CARDS_FILTER = 'SET_CARDS_FILTER'; export const FETCH_ACTIVITY = 'FETCH_ACTIVITY'; -export const FETCH_CARDS = 'FETCH_CARDS'; -export const FETCH_DATABASES = 'FETCH_DATABASES'; -export const CLEAR_DATABASE_METADATA = 'CLEAR_DATABASE_METADATA'; -export const FETCH_DATABASE_METADATA = 'FETCH_DATABASE_METADATA'; export const FETCH_RECENT_VIEWS = 'FETCH_RECENT_VIEWS'; // action creators -export const setSelectedTab = createAction(SET_SELECTED_TAB); - -export const setCardsFilter = createThunkAction(SET_CARDS_FILTER, function(filterDef) { - return function(dispatch, getState) { - let { cardsFilter } = getState(); - let { database, table } = filterDef; - - if (database && !table && database !== cardsFilter.database) { - // user has picked a database different from any previous choice - dispatch(clearDatabaseMetadata()); - dispatch(fetchDatabaseMetadata(database)); - dispatch(fetchCards('database', database)); - - } else if (database && !table && database === cardsFilter.database) { - // user is simply clearing the table selection - dispatch(fetchCards('database', database)); - - } else if (database && table) { - // user has chosen a specific table to filter on - dispatch(fetchCards('table', table)); - - } else if (!database && cardsFilter.database) { - // clearing out all filters - dispatch(fetchCards('all')); - } - - return filterDef; - }; -}); export const fetchActivity = createThunkAction(FETCH_ACTIVITY, function() { return async function(dispatch, getState) { @@ -102,31 +64,3 @@ export const fetchRecentViews = createThunkAction(FETCH_RECENT_VIEWS, function() return recentViews; }; }); - - -export const fetchCards = createThunkAction(FETCH_CARDS, function(filterMode, filterModelId) { - return async function(dispatch, getState) { - let cards = await CardApi.list({'filterMode' : filterMode, 'model_id' : filterModelId }); - for (var c of cards) { - c.created_at = moment(c.created_at); - c.updated_at = moment(c.updated_at); - c.icon = c.display ? 'illustration_visualization_' + c.display : null; - } - return cards; - }; -}); - -export const fetchDatabases = createThunkAction(FETCH_DATABASES, function() { - return async function(dispatch, getState) { - return await MetadataApi.db_list(); - }; -}); - - -export const clearDatabaseMetadata = createAction(CLEAR_DATABASE_METADATA); - -export const fetchDatabaseMetadata = createThunkAction(FETCH_DATABASE_METADATA, function(database_id) { - return async function(dispatch, getState) { - return await MetadataApi.db_metadata({'dbId': database_id}); - }; -}); diff --git a/resources/frontend_client/app/home/components/HeaderTabs.react.js b/resources/frontend_client/app/home/components/HeaderTabs.react.js deleted file mode 100644 index e3943c760f7cf4f5089665a471ab8b34c3a085cb..0000000000000000000000000000000000000000 --- a/resources/frontend_client/app/home/components/HeaderTabs.react.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; - -import React, { Component, PropTypes } from "react"; -import cx from "classnames"; - -import { setSelectedTab } from '../actions'; - - -const ACTIVITY_TAB = 'activity'; -const CARDS_TAB = 'cards'; - -export default class HeaderTabs extends Component { - - onClickActivityTab() { - if (this.props.selectedTab !== ACTIVITY_TAB) { - this.props.dispatch(setSelectedTab(ACTIVITY_TAB)); - } - } - - onClickQuestionsTab() { - if (this.props.selectedTab !== CARDS_TAB) { - this.props.dispatch(setSelectedTab(CARDS_TAB)); - } - } - - render() { - const { selectedTab } = this.props; - - const activityTab = cx({ - 'HomeTab': true, - 'inline-block': true, - 'HomeTab--active': (selectedTab === ACTIVITY_TAB), - 'text-dark': (selectedTab === ACTIVITY_TAB) - }); - const questionsTab = cx({ - 'HomeTab': true, - 'inline-block': true, - 'HomeTab--active': (selectedTab === CARDS_TAB), - 'text-dark': (selectedTab === CARDS_TAB) - }); - - return ( - <div className="text-white" style={{backgroundColor: 'transparent'}}> - <a className={activityTab} style={{marginLeft: '10px'}} href="/">Activity</a> - <a className={questionsTab} href="/?questions">Saved Questions</a> - </div> - ); - } -} - -HeaderTabs.propTypes = { - selectedTab: PropTypes.string.isRequired -} diff --git a/resources/frontend_client/app/home/components/Homepage.react.js b/resources/frontend_client/app/home/components/Homepage.react.js index f44a2ed58ab0eee4090ed7450b67ca83a67b0c0d..f88f8f42a86be1b343b2dbbb4636b3f481d16967 100644 --- a/resources/frontend_client/app/home/components/Homepage.react.js +++ b/resources/frontend_client/app/home/components/Homepage.react.js @@ -5,11 +5,8 @@ import React, { Component, PropTypes } from "react"; import Greeting from "metabase/lib/greeting"; import Modal from "metabase/components/Modal.react"; -import HeaderTabs from "./HeaderTabs.react"; import Activity from "./Activity.react"; -import Cards from "./Cards.react"; import RecentViews from "./RecentViews.react"; -import CardFilters from "./CardFilters.react"; import Smile from './Smile.react'; import NewUserOnboardingModal from './NewUserOnboardingModal.react'; @@ -38,7 +35,7 @@ export default class Homepage extends Component { } render() { - const { selectedTab, user } = this.props; + const { user } = this.props; return ( <div className="flex flex-column flex-full"> @@ -51,37 +48,23 @@ export default class Homepage extends Component { <div className="CheckBg bg-brand text-white md-pl4"> <div className="HomeLayout"> <div className="HomeLayout-mainColumn"> - <header style={this.styles.headerGreeting} className="flex align-center pb4"> + <header style={this.styles.headerGreeting} className="flex align-center pb4 pt1"> <span className="float-left mr1"> <Smile /> </span> <span>{(user) ? this.state.greeting + ' ' + user.first_name : this.state.greeting}</span> </header> - <div className=""> - <span className="float-left UserNick bg-brand text-brand mr3"> - <span className="UserInitials">MB</span> - </span> - <HeaderTabs {...this.props} /> - </div> </div> </div> </div> <div className="relative felx flex-column flex-full md-pl4"> <div className="HomeLayout"> <div className="HomeLayout-mainColumn"> - { selectedTab === 'activity' ? - <Activity {...this.props} /> - : - <Cards {...this.props} /> - } + <Activity {...this.props} /> </div> </div> <div className="HomeLayout-sidebar"> - { selectedTab === 'activity' ? - <RecentViews {...this.props} /> - : - <CardFilters {...this.props} /> - } + <RecentViews {...this.props} /> </div> </div> </div> @@ -93,6 +76,5 @@ Homepage.propTypes = { dispatch: PropTypes.func.isRequired, onChangeLocation: PropTypes.func.isRequired, showOnboarding: PropTypes.bool.isRequired, - selectedTab: PropTypes.string.isRequired, user: PropTypes.object.isRequired }; diff --git a/resources/frontend_client/app/home/home.controllers.js b/resources/frontend_client/app/home/home.controllers.js index 149e06eae7408162e0f096f76d119e87ce45ab28..fb77e421df03e608270d66175c51f4bfbbc6ae65 100644 --- a/resources/frontend_client/app/home/home.controllers.js +++ b/resources/frontend_client/app/home/home.controllers.js @@ -6,20 +6,12 @@ import thunkMidleware from "redux-thunk"; import HomepageApp from './containers/HomepageApp.react'; import * as reducers from './reducers'; -import { setSelectedTab } from './actions'; - -// import { devTools, persistState } from 'redux-devtools'; -// import { LogMonitor } from 'redux-devtools/lib/react'; -// import loggerMiddleware from 'redux-logger'; const finalCreateStore = compose( applyMiddleware( thunkMidleware, promiseMiddleware - // ,loggerMiddleware ), - // devTools(), - // persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)), createStore ); @@ -36,36 +28,5 @@ HomeControllers.controller('Homepage', ['$scope', '$location', '$route', '$route $scope.$apply(() => $location.url(url)); } }; - $scope.store = finalCreateStore(reducer, { selectedTab: 'activity' }); - - // $scope.monitor = LogMonitor; - - // mildly hacky way to prevent reloading controllers as the URL changes - var route = $route.current; - $scope.$on('$locationChangeSuccess', function (event) { - var newParams = $route.current.params; - var oldParams = route.params; - - if ($route.current.$$route.controller === 'Homepage') { - $route.current = route; - - angular.forEach(oldParams, function(value, key) { - delete $route.current.params[key]; - delete $routeParams[key]; - }); - angular.forEach(newParams, function(value, key) { - $route.current.params[key] = value; - $routeParams[key] = value; - }); - } - }); - - $scope.routeParams = $routeParams; - $scope.$watch('routeParams', function() { - if ($scope.routeParams.questions === true) { - $scope.store.dispatch(setSelectedTab('cards')); - } else { - $scope.store.dispatch(setSelectedTab('activity')); - } - }, true); + $scope.store = finalCreateStore(reducer, { }); }]); diff --git a/resources/frontend_client/app/home/reducers.js b/resources/frontend_client/app/home/reducers.js index 2a88f4303a4355ef8402639d4be7163546710bc4..eedfda64193147852b961c6b07957be7a47f42bb 100644 --- a/resources/frontend_client/app/home/reducers.js +++ b/resources/frontend_client/app/home/reducers.js @@ -3,25 +3,11 @@ import { handleActions } from 'redux-actions'; import { - SET_SELECTED_TAB, - SET_CARDS_FILTER, FETCH_ACTIVITY, - FETCH_CARDS, - FETCH_DATABASES, - CLEAR_DATABASE_METADATA, - FETCH_DATABASE_METADATA, FETCH_RECENT_VIEWS } from './actions'; -export const selectedTab = handleActions({ - [SET_SELECTED_TAB]: { next: (state, { payload }) => payload } -}, 'activity'); - -export const cardsFilter = handleActions({ - [SET_CARDS_FILTER]: { next: (state, { payload }) => payload } -}, {database: null, table: null}); - export const activity = handleActions({ [FETCH_ACTIVITY]: { next: (state, { payload }) => payload } @@ -30,20 +16,3 @@ export const activity = handleActions({ export const recentViews = handleActions({ [FETCH_RECENT_VIEWS]: { next: (state, { payload }) => payload } }, []); - - -export const cards = handleActions({ - [FETCH_CARDS]: { next: (state, { payload }) => payload } -}, null); - - -export const databases = handleActions({ - [FETCH_DATABASES]: { next: (state, { payload }) => payload } -}, []); - - -export const databaseMetadata = handleActions({ - [FETCH_DATABASE_METADATA]: { next: (state, { payload }) => payload }, - [CLEAR_DATABASE_METADATA]: { next: (state, { payload }) => null } -}, null); - diff --git a/resources/frontend_client/app/home/selectors.js b/resources/frontend_client/app/home/selectors.js index d60d162cbe3e7fa3f96373dd43f4d65f8ea68612..3f5ec54fd3f89c8ae8a0748965d35564940e705b 100644 --- a/resources/frontend_client/app/home/selectors.js +++ b/resources/frontend_client/app/home/selectors.js @@ -2,21 +2,9 @@ import { createSelector } from 'reselect'; - -const selectedTabSelector = state => state.selectedTab; -const cardsFilterSelector = state => state.cardsFilter; - -const activitySelector = state => state.activity; -const recentViewsSelector = state => state.recentViews; - -const cardsSelector = state => state.cards; - -const databasesSelector = state => state.databases; -const databaseMetadataSelector = state => state.databaseMetadata; - - -// our master selector which combines all of our partial selectors above export const homepageSelectors = createSelector( - [selectedTabSelector, cardsFilterSelector, activitySelector, recentViewsSelector, cardsSelector, databasesSelector, databaseMetadataSelector], - (selectedTab, cardsFilter, activity, recentViews, cards, databases, databaseMetadata) => ({selectedTab, cardsFilter, activity, recentViews, cards, databases, databaseMetadata}) + [state => state.activity, + state => state.recentViews], + + (activity, recentViews) => ({activity, recentViews}) ); \ No newline at end of file