Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Created session helper for newTabState #5361

Merged
merged 2 commits into from
Nov 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions app/common/state/aboutNewTabState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const Immutable = require('immutable')
const {makeImmutable} = require('./immutableUtil')
const siteUtil = require('../../../js/state/siteUtil')

const excludeSiteDetail = (siteDetail) => {
return !siteUtil.isBookmark(siteDetail) && !siteUtil.isHistoryEntry(siteDetail)
}

const removeDuplicateSites = (sites) => {
// Filter out duplicate entries by location
return sites.filter((element, index, list) => {
if (!element) return false
return index === list.findIndex((site) => site && site.get('location') === element.get('location'))
})
}

const aboutNewTabState = {
mergeDetails: (state, props) => {
state = makeImmutable(state)
if (!props) {
return state
}

state = state.mergeIn(['about', 'newtab'], props.newTabPageDetail)
return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
},

addSite: (state, props) => {
state = makeImmutable(state)
if (!props) {
return state
}

// Add timestamp if missing (ex: this is a visit, not a bookmark)
let siteDetail = makeImmutable(props.siteDetail)
siteDetail = siteDetail.set('lastAccessedTime', siteDetail.get('lastAccessedTime') || new Date().getTime())

// Only bookmarks and history items should be considered
if (excludeSiteDetail(siteDetail)) {
return state
}

// Remove tags since we've verified this is a bookmark/history item
// NOTE: siteUtil.removeSite won't delete the entry unless tags are missing
siteDetail = siteDetail.delete('tags')

// Keep track of the last 18 visited sites
let sites = state.getIn(['about', 'newtab', 'sites']) || new Immutable.List()
sites = sites.unshift(siteDetail)
sites = removeDuplicateSites(sites)
sites = sites.take(18)
// TODO(cezaraugusto): Sort should respect unshift and don't prioritize bookmarks
// |
// V
// .sort(suggestion.sortByAccessCountWithAgeDecay)
sites = siteUtil.addSite(sites, siteDetail, undefined, props.originalSiteDetail)
state = state.setIn(['about', 'newtab', 'sites'], sites)
return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
},

removeSite: (state, props) => {
state = makeImmutable(state)
if (!props) {
return state
}

// Only bookmarks and history items should be considered
let siteDetail = makeImmutable(props.siteDetail)
if (excludeSiteDetail(siteDetail)) {
return state
}

// Remove tags since we've verified this is a bookmark/history item
// NOTE: siteUtil.removeSite won't delete the entry unless tags are missing
siteDetail = siteDetail.delete('tags')

const sites = state.getIn(['about', 'newtab', 'sites'])
state = state.setIn(['about', 'newtab', 'sites'], siteUtil.removeSite(sites, siteDetail, undefined))
return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
},

updateSiteFavicon: (state, props) => {
state = makeImmutable(state)
props = makeImmutable(props)
if (!props || !props.get('frameProps') || !props.getIn(['frameProps', 'location'])) {
return state
}

const sites = state.getIn(['about', 'newtab', 'sites'])
const sitesWithFavicon = siteUtil.updateSiteFavicon(sites, props.getIn(['frameProps', 'location']), props.get('favicon'))
state = state.setIn(['about', 'newtab', 'sites'], sitesWithFavicon)
return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
}
}

module.exports = aboutNewTabState
26 changes: 5 additions & 21 deletions js/stores/appStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ const path = require('path')
const {channel} = require('../../app/channel')
const os = require('os')
const autofill = require('../../app/autofill')
// const suggestion = require('../lib/suggestion')

// state helpers
const basicAuthState = require('../../app/common/state/basicAuthState')
const extensionState = require('../../app/common/state/extensionState')
const tabState = require('../../app/common/state/tabState')
const aboutNewTabState = require('../../app/common/state/aboutNewTabState')
const isDarwin = process.platform === 'darwin'
const isWindows = process.platform === 'win32'

Expand Down Expand Up @@ -430,8 +430,7 @@ const handleAppAction = (action) => {
appState = appState.set('passwords', new Immutable.List())
break
case AppConstants.APP_CHANGE_NEW_TAB_DETAIL:
appState = appState.mergeIn(['about', 'newtab'], action.newTabPageDetail)
appState = appState.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
appState = aboutNewTabState.mergeDetails(appState, action)
break
case AppConstants.APP_ADD_SITE:
const oldSiteSize = appState.get('sites').size
Expand All @@ -449,30 +448,14 @@ const handleAppAction = (action) => {
if (oldSiteSize !== appState.get('sites').size) {
filterOutNonRecents()
}
let newVisitedSites = appState.getIn(['about', 'newtab', 'sites']) || new Immutable.List()
newVisitedSites = newVisitedSites.unshift(action.siteDetail)
// Filter duplicated entries by its location
newVisitedSites = newVisitedSites.filter((element, index, list) => {
if (!element) return false
return index === list.findIndex((site) => site && site.get('location') === element.get('location'))
})
newVisitedSites = newVisitedSites.take(18)
// TODO: @cezaraugusto.
// Sort should respect unshift and don't prioritize bookmarks
// |
// V
// .sort(suggestion.sortByAccessCountWithAgeDecay)

appState = appState.setIn(['about', 'newtab', 'sites'], siteUtil.addSite(newVisitedSites, action.siteDetail, action.tag, action.originalSiteDetail))
appState = appState.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
appState = aboutNewTabState.addSite(appState, action)
break
case AppConstants.APP_REMOVE_SITE:
appState = appState.set('sites', siteUtil.removeSite(appState.get('sites'), action.siteDetail, action.tag))
appState = appState.setIn(['about', 'newtab', 'sites'], siteUtil.removeSite(appState.getIn(['about', 'newtab', 'sites']), action.siteDetail, action.tag))
appState = aboutNewTabState.removeSite(appState, action)
break
case AppConstants.APP_MOVE_SITE:
appState = appState.set('sites', siteUtil.moveSite(appState.get('sites'), action.sourceDetail, action.destinationDetail, action.prepend, action.destinationIsParent, false))
appState = appState.setIn(['about', 'newtab', 'sites'], siteUtil.moveSite(appState.getIn(['about', 'newtab', 'sites']), action.sourceDetail, action.destinationDetail, action.prepend, action.destinationIsParent, false))
break
case AppConstants.APP_MERGE_DOWNLOAD_DETAIL:
if (action.downloadDetail) {
Expand Down Expand Up @@ -792,6 +775,7 @@ const handleAppAction = (action) => {
break
case WindowConstants.WINDOW_SET_FAVICON:
appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon))
appState = aboutNewTabState.updateSiteFavicon(appState, action)
break
case WindowConstants.WINDOW_SET_NAVIGATED:
if (!action.isNavigatedInPage) {
Expand Down
192 changes: 192 additions & 0 deletions test/unit/common/state/aboutNewTabStateTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/* global describe, it */
const aboutNewTabState = require('../../../../app/common/state/aboutNewTabState')
const Immutable = require('immutable')
const assert = require('assert')
const siteTags = require('../../../../js/constants/siteTags')

const defaultAppState = Immutable.fromJS({
about: {
newtab: {
gridLayoutSize: 'large',
sites: [],
ignoredTopSites: [],
pinnedTopSites: [],
updatedStamp: undefined
}
}
})

const arbitraryTimeInThePast = 1450000000000

const assertTimeUpdated = (state) => {
const updatedStamp = state.getIn(['about', 'newtab', 'updatedStamp'])
assert.equal(typeof updatedStamp === 'number' && updatedStamp > arbitraryTimeInThePast, true)
}

const assertNoChange = (state) => {
const updatedStamp = state.getIn(['about', 'newtab', 'updatedStamp'])
assert.deepEqual(state, defaultAppState)
assert.equal(updatedStamp, undefined)
}

describe('aboutNewTabState', function () {
const testTime = 1478213227349
const bookmarkFolderAction = {
siteDetail: {
location: 'https://brave.com',
tags: [siteTags.BOOKMARK_FOLDER],
customTitle: 'folder 1',
parentFolderId: 0,
folderId: 1,
lastAccessedTime: testTime
}
}
const aboutPageAction = {
siteDetail: {
location: 'about:preferences',
title: 'preferences',
lastAccessedTime: testTime
}
}
const bookmarkAction = {
siteDetail: {
title: 'Brave',
location: 'https://brave.com',
lastAccessedTime: testTime
},
tag: siteTags.BOOKMARK
}

describe('mergeDetails', function () {
it('updates the `updatedStamp` value on success', function () {
const action = {newTabPageDetail: {}}
const state = aboutNewTabState.mergeDetails(defaultAppState, action)
assertTimeUpdated(state)
})

it('does not update state or `updatedStamp` if input is falsey', function () {
const state = aboutNewTabState.mergeDetails(defaultAppState, null)
assertNoChange(state)
})

it('merges the provided data into about.newtab', function () {
const action = {newTabPageDetail: {testing123: 'TEST STRING'}}
const state = aboutNewTabState.mergeDetails(defaultAppState, action)
const updatedValue = state.getIn(['about', 'newtab', 'testing123'])
assert.equal(updatedValue, 'TEST STRING')
})
})

describe('addSite', function () {
it('updates the `updatedStamp` value on success', function () {
const state = aboutNewTabState.addSite(defaultAppState, bookmarkAction)
assertTimeUpdated(state)
})

describe('does not update state or `updatedStamp` if input is invalid', function () {
it('calls with props=falsey', function () {
const state = aboutNewTabState.addSite(defaultAppState, null)
assertNoChange(state)
})

it('calls with props=bookmark folder', function () {
const state = aboutNewTabState.addSite(defaultAppState, bookmarkFolderAction)
assertNoChange(state)
})

it('calls with props=about page', function () {
const state = aboutNewTabState.addSite(defaultAppState, aboutPageAction)
assertNoChange(state)
})
})

it('adds the entry into the sites list', function () {
const state = aboutNewTabState.addSite(defaultAppState, bookmarkAction)
const updatedValue = state.getIn(['about', 'newtab', 'sites', 0, 'location'])
assert.equal(updatedValue, bookmarkAction.siteDetail.location)
})

it('removes the tags when adding to the sites list', function () {
const state = aboutNewTabState.addSite(defaultAppState, bookmarkAction)
const updatedValue = state.getIn(['about', 'newtab', 'sites', 0, 'tags'])
assert.deepEqual(updatedValue.toJS(), [])
})

it('will add lastAccessedTime to the siteDetail if missing from history entry', function () {
const action = {siteDetail: {location: 'https://brave.com'}}
const state = aboutNewTabState.addSite(defaultAppState, action)
const updatedValue = state.getIn(['about', 'newtab', 'sites', 0, 'lastAccessedTime'])
assert.equal(typeof updatedValue === 'number' && updatedValue > arbitraryTimeInThePast, true)
})
})

describe('removeSite', function () {
it('updates the `updatedStamp` value on success', function () {
const action = {siteDetail: {location: 'https://brave.com', lastAccessedTime: testTime}}
const state = aboutNewTabState.removeSite(defaultAppState, action)
assertTimeUpdated(state)
})

describe('does not update state or `updatedStamp` if input is invalid', function () {
it('calls with props=falsey', function () {
const state = aboutNewTabState.removeSite(defaultAppState, null)
assertNoChange(state)
})

it('calls with props=bookmark folder', function () {
const state = aboutNewTabState.removeSite(defaultAppState, bookmarkFolderAction)
assertNoChange(state)
})

it('calls with props=about page', function () {
const state = aboutNewTabState.addSite(defaultAppState, aboutPageAction)
assertNoChange(state)
})
})

it('removes the entry from the sites list', function () {
const stateWithSite = aboutNewTabState.addSite(defaultAppState, bookmarkAction)
assert.equal(stateWithSite.size, 1)

const state = aboutNewTabState.removeSite(stateWithSite, bookmarkAction)
const sites = state.getIn(['about', 'newtab', 'sites'])
assert.equal(sites.size, 0)
})
})

describe('updateSiteFavicon', function () {
it('updates the `updatedStamp` value on success', function () {
const action = {frameProps: {location: 'https://brave.com'}, favicon: 'https://brave.com/favicon.ico'}
const state = aboutNewTabState.updateSiteFavicon(defaultAppState, action)
assertTimeUpdated(state)
})

describe('does not update state or `updatedStamp` if input is invalid', function () {
it('calls with props=falsey', function () {
const state = aboutNewTabState.updateSiteFavicon(defaultAppState, null)
assertNoChange(state)
})
it('calls with props.frameProps=null', function () {
const action = {frameProps: null}
const state = aboutNewTabState.updateSiteFavicon(defaultAppState, action)
assertNoChange(state)
})
it('calls with props.frameProps.location=null', function () {
const action = {frameProps: {location: null}}
const state = aboutNewTabState.updateSiteFavicon(defaultAppState, action)
assertNoChange(state)
})
})

it('updates the entry into the sites list', function () {
let state = aboutNewTabState.addSite(defaultAppState, bookmarkAction)
let favicon = state.getIn(['about', 'newtab', 'sites', 0, 'favicon'])
assert.equal(favicon, undefined)

const action = {frameProps: {location: 'https://brave.com'}, favicon: 'https://brave.com/favicon.ico'}
state = aboutNewTabState.updateSiteFavicon(state, action)
favicon = state.getIn(['about', 'newtab', 'sites', 0, 'favicon'])
assert.equal(favicon, action.favicon)
})
})
})