diff --git a/app/common/state/tabContentState/partitionState.js b/app/common/state/tabContentState/partitionState.js index c8fc879c2ab..c974987acc3 100644 --- a/app/common/state/tabContentState/partitionState.js +++ b/app/common/state/tabContentState/partitionState.js @@ -3,6 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ // State helpers +const tabUIState = require('../tabUIState') const frameStateUtil = require('../../../../js/state/frameStateUtil') // Constants @@ -54,3 +55,19 @@ module.exports.getMaxAllowedPartitionNumber = (state, frameKey) => { } return partitionNumber } + +module.exports.showPartitionIcon = (state, frameKey) => { + const frame = frameStateUtil.getFrameByKey(state, frameKey) + + if (frame == null) { + if (process.env.NODE_ENV !== 'test') { + console.error('Unable to find frame for showPartitionIcon method') + } + return false + } + + return ( + module.exports.isPartitionTab(state, frameKey) && + tabUIState.showTabEndIcon(state, frameKey) + ) +} diff --git a/app/renderer/components/tabs/content/newSessionIcon.js b/app/renderer/components/tabs/content/newSessionIcon.js index 303b902661f..0c7fed78225 100644 --- a/app/renderer/components/tabs/content/newSessionIcon.js +++ b/app/renderer/components/tabs/content/newSessionIcon.js @@ -1,22 +1,18 @@ /* 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/. */ +* 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 React = require('react') const {StyleSheet, css} = require('aphrodite/no-important') -const Immutable = require('immutable') // Components const ReduxComponent = require('../../reduxComponent') const TabIcon = require('./tabIcon') // State +const partitionState = require('../../../../common/state/tabContentState/partitionState') const tabUIState = require('../../../../common/state/tabUIState') - -// Constants -const {tabs} = require('../../../../../js/constants/config') - -// Utils +const tabState = require('../../../../common/state/tabState') const frameStateUtil = require('../../../../../js/state/frameStateUtil') // Styles @@ -26,45 +22,42 @@ const newSessionSvg = require('../../../../extensions/brave/img/tabs/new_session class NewSessionIcon extends React.Component { mergeProps (state, ownProps) { const currentWindow = state.get('currentWindow') - const frameKey = ownProps.frameKey - const frame = frameStateUtil.getFrameByKey(currentWindow, frameKey) || Immutable.Map() - const partition = frame.get('partitionNumber') - const hasSeconardImage = tabUIState.hasVisibleSecondaryIcon(currentWindow, ownProps.frameKey) + const tabId = ownProps.tabId + const frameKey = frameStateUtil.getFrameKeyByTabId(currentWindow, tabId) const props = {} - // used in renderer - props.showSessionIcon = !!partition && hasSeconardImage + props.isPinned = tabState.isTabPinned(state, tabId) + props.showPartitionIcon = partitionState.showPartitionIcon(currentWindow, frameKey) props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, frameKey) - props.iconColor = tabUIState.getTabIconColor(currentWindow, frameKey) - props.partitionNumber = typeof partition === 'string' - ? partition.replace(/^partition-/i, '') - : partition - props.partitionIndicator = props.partitionNumber > tabs.maxAllowedNewSessions - ? tabs.maxAllowedNewSessions - : props.partitionNumber - - // used in functions - props.frameKey = frameKey + props.textIsWhite = tabUIState.checkIfTextColor(currentWindow, frameKey, 'white') + props.partitionNumber = partitionState.getMaxAllowedPartitionNumber(currentWindow, frameKey) + props.tabId = tabId return props } render () { - if (!this.props.showSessionIcon) { + if ( + this.props.isPinned || + !this.props.showPartitionIcon || + this.props.partitionNumber === 0 + ) { return null } - const newSession = StyleSheet.create({ - indicator: { - // Based on getTextColorForBackground() icons can be only black or white. - filter: this.props.isActive && this.props.iconColor === 'white' ? 'invert(100%)' : 'none' + + const newSessionProps = StyleSheet.create({ + newSession__indicator: { + filter: this.props.isActive && this.props.textIsWhite + ? 'invert(100%)' + : 'none' } }) return } @@ -73,21 +66,17 @@ class NewSessionIcon extends React.Component { module.exports = ReduxComponent.connect(NewSessionIcon) const styles = StyleSheet.create({ - icon: { + newSession__icon: { + zIndex: globalStyles.zindex.zindexWindow, + boxSizing: 'border-box', + display: 'flex', + alignItems: 'center', + backgroundImage: `url(${newSessionSvg})`, + backgroundPosition: 'center left', + backgroundRepeat: 'no-repeat', + backgroundSize: '13px', width: globalStyles.spacing.iconSize, - minWidth: globalStyles.spacing.iconSize, height: globalStyles.spacing.iconSize, - backgroundSize: globalStyles.spacing.iconSize, - fontSize: globalStyles.fontSize.tabIcon, - backgroundPosition: 'center', - backgroundRepeat: 'no-repeat', - paddingLeft: globalStyles.spacing.defaultIconPadding, - paddingRight: globalStyles.spacing.defaultIconPadding - }, - - newSession: { - position: 'relative', - backgroundImage: `url(${newSessionSvg})`, - backgroundPosition: 'left' + marginRight: globalStyles.spacing.defaultTabMargin } }) diff --git a/app/renderer/components/tabs/tab.js b/app/renderer/components/tabs/tab.js index 5ccf1909af3..1fa497944ba 100644 --- a/app/renderer/components/tabs/tab.js +++ b/app/renderer/components/tabs/tab.js @@ -371,7 +371,7 @@ class Tab extends React.Component { - + diff --git a/test/unit/app/renderer/components/tabs/content/newSessionIconTest.js b/test/unit/app/renderer/components/tabs/content/newSessionIconTest.js index 7643642eb28..24470da8fdb 100644 --- a/test/unit/app/renderer/components/tabs/content/newSessionIconTest.js +++ b/test/unit/app/renderer/components/tabs/content/newSessionIconTest.js @@ -7,38 +7,39 @@ const mockery = require('mockery') const {mount} = require('enzyme') const assert = require('assert') const Immutable = require('immutable') -const {tabs} = require('../../../../../../../js/constants/config') const fakeElectron = require('../../../../../lib/fakeElectron') +const {intersection} = require('../../../../../../../app/renderer/components/styles/global') require('../../../../../braveUnit') const index = 0 const tabId = 1 const frameKey = 1 -const invalidFrameKey = 71 -const fakeAppStoreRenderer = { - state: Immutable.fromJS({ - windows: [{ - windowId: 1, - windowUUID: 'uuid' - }], - tabs: [{ - tabId: tabId, - windowId: 1, - windowUUID: 'uuid', - url: 'https://brave.com' - }] - }), - addChangeListener: () => {}, - removeChangeListener: () => {} -} +const fakeAppStoreRenderer = Immutable.fromJS({ + windows: [{ + windowId: 1, + windowUUID: 'uuid' + }], + tabs: [{ + tabId: tabId, + windowId: 1, + windowUUID: 'uuid', + url: 'https://brave.com' + }], + tabsInternal: { + index: { + 1: 0 + } + } +}) const defaultWindowStore = Immutable.fromJS({ activeFrameKey: frameKey, frames: [{ key: frameKey, tabId: tabId, - location: 'http://brave.com' + location: 'http://brave.com', + partitionNumber: 1 }], tabs: [{ key: frameKey, @@ -54,13 +55,13 @@ const defaultWindowStore = Immutable.fromJS({ }, ui: { tabs: { - hoverTabIndex: index + tabHoverState: 1 } } }) -describe.skip('Tabs content - NewSessionIcon', function () { - let Tab, windowStore, NewSessionIcon +describe('Tabs content - NewSessionIcon', function () { + let NewSessionIcon, windowStore, appStore before(function () { mockery.enable({ @@ -69,15 +70,11 @@ describe.skip('Tabs content - NewSessionIcon', function () { useCleanCache: true }) mockery.registerMock('electron', fakeElectron) - mockery.registerMock('../../../js/stores/appStoreRenderer', fakeAppStoreRenderer) - mockery.registerMock('../../../../extensions/brave/img/tabs/loading.svg') mockery.registerMock('../../../../extensions/brave/img/tabs/new_session.svg') - mockery.registerMock('../../../../extensions/brave/img/tabs/private.svg') - mockery.registerMock('../../../../extensions/brave/img/tabs/close_btn_hover.svg') - mockery.registerMock('../../../../extensions/brave/img/tabs/close_btn_normal.svg') windowStore = require('../../../../../../../js/stores/windowStore') - Tab = require('../../../../../../../app/renderer/components/tabs/tab') - NewSessionIcon = require('../../../../../../../app/renderer/components/tabs/content/newSessionIcon') + appStore = require('../../../../../../../js/stores/appStoreRenderer') + NewSessionIcon = require('../../../../../../../app/renderer/components/tabs/content/NewSessionIcon') + appStore.state = fakeAppStoreRenderer }) after(function () { @@ -85,195 +82,63 @@ describe.skip('Tabs content - NewSessionIcon', function () { mockery.disable() }) - describe('should show', function () { - it('icon if current tab is a new session tab', function () { - windowStore.state = defaultWindowStore.merge({ - activeFrameKey: 0, - frames: [{ - partitionNumber: 1, - breakpoint: 'default' - }], - ui: { - tabs: { - hoverTabIndex: null - } - } - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 1) - }) - - it('icon if mouse is not over tab and breakpoint is default', function () { - windowStore.state = defaultWindowStore.merge({ - activeFrameKey: 0, - frames: [{ - partitionNumber: 1, - breakpoint: 'default' - }], - ui: { - tabs: { - hoverTabIndex: null - } - } - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 1) - }) - - it('icon if mouse is not over tab and breakpoint is large', function () { - windowStore.state = defaultWindowStore.merge({ - activeFrameKey: 0, - frames: [{ - partitionNumber: 1, - breakpoint: 'large' - }], - ui: { - tabs: { - hoverTabIndex: null - } - } - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 1) - }) - - it('icon if tab is not active and breakpoint is largeMedium', function () { - windowStore.state = defaultWindowStore.merge({ - activeFrameKey: 0, - frames: [{ - partitionNumber: 1, - breakpoint: 'largeMedium' - }], - ui: { - tabs: { - hoverTabIndex: null - } - } - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 1) - }) - - it('partition number for new sessions', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 3, - breakpoint: 'default' - }) - const wrapper = mount() - assert.equal(wrapper.find('TabIcon').props().symbolContent, 3) - }) - - it('partition number for sessions with number set by opener (ex: clicking target=_blank)', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 'partition-3', - breakpoint: 'default' - }) - const wrapper = mount() - assert.equal(wrapper.find('TabIcon').props().symbolContent, 3) + describe('should show icon', function () { + it('if tab is not hovered', function * () { + windowStore.state = defaultWindowStore + .mergeIn(['ui', 'tabs'], { + intersectionRatio: intersection.noIntersection, + tabHoverIndex: 1337 + }) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 1) }) - it('max partition number even if session is bigger', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1000, - breakpoint: 'default' - }) - const wrapper = mount() - assert.equal(wrapper.find('TabIcon').props().symbolContent, tabs.maxAllowedNewSessions) - }) - it('passing in a frame key which does not exist does not fail', function () { + it('if tab is not active and size is small', function * () { windowStore.state = defaultWindowStore - const wrapper = mount() - assert(wrapper.find('TabIcon')) + .mergeIn(['ui', 'tabs'], { + tabHoverIndex: 1337, + intersectionRatio: intersection.at45 + }) + .set('activeFrameKey', 1337) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 1) }) }) describe('should not show icon', function () { - it('if current tab is not private', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: false - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) - }) - - it('if mouse is over tab and breakpoint is default', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'default' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) - }) - - it('if mouse is over tab and breakpoint is large', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'large' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) - }) - - it('if tab is active and breakpoint is largeMedium', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'largeMedium' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) - }) - - it('if breakpoint is medium', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: false, - breakpoint: 'medium' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) + it('if tab is not partitioned', function * () { + windowStore.state = defaultWindowStore + .setIn(['frames', index, 'partitionNumber'], false) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 0) }) - it('if breakpoint is mediumSmall', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: false, - breakpoint: 'mediumSmall' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) + it('if tab is being hovered', function * () { + windowStore.state = defaultWindowStore + .setIn(['ui', 'tabs', 'hoverTabIndex'], index) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 0) }) - it('if breakpoint is small', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'small' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) + it('if for active tab if size is small', function * () { + windowStore.state = defaultWindowStore + .setIn(['ui', 'tabs', 'intersectionRatio'], intersection.at45) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 0) }) - it('if breakpoint is extraSmall', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'extraSmall' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) + it('if tab is being intersected at 35% or less', function * () { + windowStore.state = defaultWindowStore + .setIn(['ui', 'tabs', 'intersectionRatio'], intersection.at20) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 0) }) - it('if breakpoint is the smallest', function () { - windowStore.state = defaultWindowStore.mergeIn(['frames', 0], { - partitionNumber: 1, - hoverState: true, - breakpoint: 'smallest' - }) - const wrapper = mount() - assert.equal(wrapper.find('NewSessionIcon').length, 0) + it('if partitionNumber is zero', function * () { + windowStore.state = defaultWindowStore + .setIn(['frames', index, 'partitionNumber'], 0) + const wrapper = mount() + assert.equal(wrapper.find('TabIcon').length, 0) }) }) })