This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
35 changed files
with
1,052 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React from 'react'; | ||
|
||
export const ChannelsIcon = () => { | ||
return ( | ||
<svg | ||
width='24' | ||
height='24' | ||
viewBox='0 0 24 24' | ||
fill='none' | ||
xmlns='http://www.w3.org/2000/svg' | ||
> | ||
<path | ||
fillRule='evenodd' | ||
clipRule='evenodd' | ||
d='M9.89999 16.8C14.3735 16.8 18 13.7108 18 9.9C18 6.08924 14.3735 3 9.89999 3C5.42648 3 1.79999 6.08924 1.79999 9.9C1.79999 12.2671 3.19927 14.3558 5.33165 15.5987L5.33165 18.0626C5.33165 18.3023 5.5688 18.466 5.75977 18.358L8.65831 16.7194C9.0631 16.7725 9.47777 16.8 9.89999 16.8ZM16.5 19.5723C13.0728 19.5723 10.2945 17.2056 10.2945 14.2862C10.2945 11.3667 13.0728 9 16.5 9C19.9272 9 22.7055 11.3667 22.7055 14.2862C22.7055 16.0997 21.6334 17.7 19.9996 18.6521V20.4139C19.9996 20.6536 19.7625 20.8173 19.5715 20.7093L17.4511 19.5106C17.141 19.5513 16.8234 19.5723 16.5 19.5723Z' | ||
fill='blue' | ||
/> | ||
</svg> | ||
); | ||
}; | ||
|
||
export const SwitcherIcon = () => { | ||
return ( | ||
<svg | ||
width='14' | ||
height='13' | ||
viewBox='0 0 14 13' | ||
fill='inherit' | ||
xmlns='http://www.w3.org/2000/svg' | ||
> | ||
<path | ||
d='M9.98828 12.5618H13.0117V9.53833H9.98828V12.5618ZM9.98828 8.06177H13.0117V5.03833H9.98828V8.06177ZM5.48828 3.56177H8.51172V0.53833H5.48828V3.56177ZM9.98828 3.56177H13.0117V0.53833H9.98828V3.56177ZM5.48828 8.06177H8.51172V5.03833H5.48828V8.06177ZM0.988281 8.06177H4.01172V5.03833H0.988281V8.06177ZM0.988281 12.5618H4.01172V9.53833H0.988281V12.5618ZM5.48828 12.5618H8.51172V9.53833H5.48828V12.5618ZM0.988281 3.56177H4.01172V0.53833H0.988281V3.56177Z' | ||
fill='inherit' | ||
/> | ||
</svg> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React from 'react'; | ||
import {shallow} from 'enzyme'; | ||
|
||
import * as redux from 'react-redux'; | ||
|
||
import GlobalHeader from 'components/global/global_header'; | ||
|
||
import * as hooks from './hooks'; | ||
|
||
describe('components/global/global_header', () => { | ||
test('should be disabled when global header is disabled', () => { | ||
const spy = jest.spyOn(redux, 'useSelector'); | ||
spy.mockReturnValue(false); | ||
const spyProduct = jest.spyOn(hooks, 'useCurrentProductId'); | ||
spyProduct.mockReturnValue(null); | ||
|
||
const wrapper = shallow( | ||
<GlobalHeader/>, | ||
); | ||
|
||
// Global header should render null | ||
expect(wrapper.type()).toEqual(null); | ||
}); | ||
|
||
test('should be enabled when global header is enabled', () => { | ||
const spy = jest.spyOn(redux, 'useSelector'); | ||
spy.mockReturnValue(true); | ||
const spyProduct = jest.spyOn(hooks, 'useCurrentProductId'); | ||
spyProduct.mockReturnValue(null); | ||
|
||
const wrapper = shallow( | ||
<GlobalHeader/>, | ||
); | ||
|
||
// Global header should not be null | ||
expect(wrapper.type()).not.toEqual(null); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import React from 'react'; | ||
import {useSelector} from 'react-redux'; | ||
|
||
import styled from 'styled-components'; | ||
|
||
import {getGlobalHeaderEnabled} from 'selectors/global_header'; | ||
import StatusDropdown from 'components/status_dropdown'; | ||
|
||
import Pluggable from 'plugins/pluggable'; | ||
|
||
import ProductSwitcher from './product_switcher'; | ||
import {useCurrentProductId, useProducts} from './hooks'; | ||
|
||
const HeaderContainer = styled.div` | ||
position: relative; | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
height: 40px; | ||
background: var(--sidebar-teambar-bg); | ||
color: var(--sidebar-text); | ||
`; | ||
|
||
const AppSpectificContent = styled.div` | ||
flex-grow: 1; | ||
`; | ||
|
||
const ProfileWrapper = styled.div` | ||
margin-right: 20px; | ||
`; | ||
|
||
const GlobalHeader = () => { | ||
const enabled = useSelector(getGlobalHeaderEnabled); | ||
const products = useProducts(); | ||
const currentProductID = useCurrentProductId(products); | ||
|
||
if (!enabled) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<HeaderContainer> | ||
<ProductSwitcher/> | ||
<AppSpectificContent> | ||
{currentProductID !== null && | ||
<Pluggable | ||
pluggableName={'Product'} | ||
subComponentName={'headerComponent'} | ||
pluggableId={currentProductID} | ||
/> | ||
} | ||
{/*currentProductID === null && | ||
This is where the header content for the webapp will go | ||
*/} | ||
</AppSpectificContent> | ||
<ProfileWrapper> | ||
<StatusDropdown | ||
globalHeader={true} | ||
/> | ||
</ProfileWrapper> | ||
</HeaderContainer> | ||
); | ||
}; | ||
|
||
export default GlobalHeader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||
// See LICENSE.txt for license information. | ||
|
||
import {MutableRefObject, useEffect} from 'react'; | ||
import {useSelector} from 'react-redux'; | ||
import {useLocation} from 'react-router'; | ||
|
||
import {GlobalState} from 'types/store'; | ||
import {ProductComponent} from 'types/store/plugins'; | ||
import {getBasePath} from 'utils/url'; | ||
|
||
const selectProducts = (state: GlobalState) => state.plugins.components.Product; | ||
|
||
export const useProducts = (): ProductComponent[] | undefined => { | ||
return useSelector<GlobalState, ProductComponent[]>(selectProducts); | ||
}; | ||
|
||
/** | ||
* Hook that alerts clicks outside of the passed ref. | ||
*/ | ||
export function useClickOutsideRef(ref: MutableRefObject<HTMLElement | null>, handler: () => void): void { | ||
useEffect(() => { | ||
function onMouseDown(event: MouseEvent) { | ||
const target = event.target as any; | ||
if (ref.current && target instanceof Node && !ref.current.contains(target)) { | ||
handler(); | ||
} | ||
} | ||
|
||
// Bind the event listener | ||
document.addEventListener('mousedown', onMouseDown); | ||
return () => { | ||
// Unbind the event listener on clean up | ||
document.removeEventListener('mousedown', onMouseDown); | ||
}; | ||
}, [ref, handler]); | ||
} | ||
|
||
export const useCurrentProductId = (products?: ProductComponent[]): string | null => { | ||
if (!products) { | ||
return null; | ||
} | ||
|
||
const location = useLocation(); | ||
for (let i = 0; i < products.length; i++) { | ||
const product = products[i]; | ||
if (location.pathname.startsWith(getBasePath() + product.baseURL)) { | ||
return product.id; | ||
} | ||
} | ||
|
||
return null; | ||
}; | ||
|
Oops, something went wrong.