Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canny Support #1282

Merged
merged 4 commits into from
Feb 22, 2021
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
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = {
'\\.(css|less)$': '<rootDir>/test_utils/__mocks__/styleMock.js',
'^browser-styles(.*)$': '<rootDir>/src/browser/styles$1',
'^browser-components(.*)$': '<rootDir>/src/browser/components$1',
'^browser-services(.*)$': '<rootDir>/src/browser/services$1',
'^browser-hooks(.*)$': '<rootDir>/src/browser/hooks$1',
'worker-loader': '<rootDir>/test_utils/__mocks__/workerLoaderMock.js',
'project-root(.*)$': '<rootDir>$1',
Expand Down
72 changes: 44 additions & 28 deletions src/browser/AppInit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
combineReducers,
applyMiddleware,
compose,
AnyAction
AnyAction,
StoreEnhancer
} from 'redux'
import { Provider } from 'react-redux'
import {
Expand All @@ -42,7 +43,9 @@ import * as Sentry from '@sentry/react'
import { Integrations } from '@sentry/tracing'
import { CaptureConsole } from '@sentry/integrations'

import { CannySDK } from 'browser-services/canny'
import { createReduxMiddleware, getAll, applyKeys } from 'services/localstorage'
import { GlobalState } from 'shared/globalState'
import { APP_START } from 'shared/modules/app/appDuck'
import { detectRuntimeEnv } from 'services/utils'
import { NEO4J_CLOUD_DOMAINS } from 'shared/modules/settings/settingsDuck'
Expand Down Expand Up @@ -70,13 +73,20 @@ const suberMiddleware = createSuberReduxMiddleware(bus)
const epicMiddleware = createEpicMiddleware(epics)
const localStorageMiddleware = createReduxMiddleware()

const reducer = combineReducers({ ...(reducers as any) })
const reducer = combineReducers<GlobalState>({ ...(reducers as any) })

const enhancer = compose(
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION__?: (
...args: unknown[]
) => StoreEnhancer<unknown>
}
}

const enhancer: StoreEnhancer<GlobalState> = compose(
applyMiddleware(suberMiddleware, epicMiddleware, localStorageMiddleware),
process.env.NODE_ENV !== 'production' &&
(window as any).__REDUX_DEVTOOLS_EXTENSION__
? (window as any).__REDUX_DEVTOOLS_EXTENSION__({
process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION__({
actionSanitizer: (action: AnyAction) =>
action.type === 'requests/UPDATED'
? {
Expand All @@ -88,52 +98,50 @@ const enhancer = compose(
}
}
: action,
stateSanitizer: (state: any) => ({
stateSanitizer: (state: GlobalState) => ({
...state,
requests: Object.assign(
{},
...Object.entries(state.requests).map(
([id, request]: [string, any]) => ({
[id]: {
...request,
result: {
...request.result,
records:
'REQUEST RECORDS OMITTED FROM REDUX DEVTOOLS TO PREVENT OUT OF MEMORY ERROR'
}
...Object.entries(state.requests).map(([id, request]) => ({
[id]: {
...request,
result: {
...request.result,
records:
'REQUEST RECORDS OMITTED FROM REDUX DEVTOOLS TO PREVENT OUT OF MEMORY ERROR'
}
})
)
}
}))
)
})
})
: (f: any) => f
: (f: unknown) => f
)

const store: any = createStore(
const store = createStore<GlobalState>(
reducer,
getAll(), // rehydrate from local storage on app start
getAll() as GlobalState, // rehydrate from local storage on app start
enhancer
)

// Send everything from suber into Redux
bus.applyMiddleware(
(_, origin) => (channel: any, message: any, source: any) => {
(_, origin) => (channel: string, message: AnyAction, source: string) => {
// No loop-backs
if (source === 'redux') return
// Send to Redux with the channel as the action type
store.dispatch({ ...message, type: channel, ...origin })
}
)

function scrubQueryparams(event: Sentry.Event): Sentry.Event {
function scrubQueryParams(event: Sentry.Event): Sentry.Event {
if (event.request?.query_string) {
event.request.query_string = ''
}
return event
}

export function setupSentry() {
export function setupSentry(): void {
if (process.env.NODE_ENV === 'production') {
Sentry.init({
dsn:
Expand All @@ -146,7 +154,7 @@ export function setupSentry() {
tracesSampleRate: 0.2,
beforeSend: event =>
allowOutgoingConnections(store.getState())
? scrubQueryparams(event)
? scrubQueryParams(event)
: null,
environment: 'unset'
})
Expand All @@ -166,7 +174,7 @@ export function setupSentry() {
}))
)
})
.catch(() => {})
.catch(() => undefined)
}
}

Expand Down Expand Up @@ -231,9 +239,17 @@ const client = new ApolloClient({
link: uploadLink
})

const AppInit = () => {
CannySDK.init()
.then(() => {
window.CannyIsLoaded = true
})
.catch(() => {
window.CannyIsLoaded = false
})

const AppInit = (): JSX.Element => {
return (
<Provider store={store}>
<Provider store={store as any}>
<BusProvider bus={bus}>
<ApolloProvider client={client}>
<App />
Expand Down
96 changes: 69 additions & 27 deletions src/browser/components/TabNavigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import React, { Component } from 'react'
import {
StyledNavigationButton,
NavigationButtonContainer
NavigationButtonContainer,
StyledCannyBadgeAnchor
} from 'browser-components/buttons'
import { cannyOptions } from 'browser-services/canny'
import {
StyledSidebar,
StyledDrawer,
Expand All @@ -36,26 +38,61 @@ const Closed = 'CLOSED'
const Open = 'OPEN'
const Opening = 'OPENING'

type State = any
export interface NavItem {
name: string
title: string
icon: (isOpen: boolean) => JSX.Element
content: any
enableCannyBadge?: boolean
}

interface NavigationProps {
openDrawer: string
onNavClick: (name: string) => void
topNavItems: NavItem[]
bottomNavItems?: NavItem[]
}

type TransitionState =
| typeof Closing
| typeof Closed
| typeof Open
| typeof Opening

interface NavigationState {
transitionState?: TransitionState
drawerContent?: null | string
}

class Navigation extends Component<any, State> {
_onTransitionEnd: any
transitionState: any
state: any = {}
constructor(props: {}) {
class Navigation extends Component<NavigationProps, NavigationState> {
_onTransitionEnd: () => void
transitionState?: TransitionState
state: NavigationState = {}
constructor(props: NavigationProps) {
super(props)
this._onTransitionEnd = this.onTransitionEnd.bind(this)
}

componentDidMount() {
componentDidMount(): void {
this.setState({
transitionState: Closed
})

window.Canny && window.Canny('initChangelog', cannyOptions)
}

componentWillUnmount(): void {
if (window.Canny) {
window.Canny('closeChangelog')
}
}

componentDidUpdate(prevProps: any, prevState: State) {
componentDidUpdate(
prevProps: NavigationProps,
prevState: NavigationState
): void {
if (prevProps.openDrawer !== this.props.openDrawer) {
const newState: any = {}
const newState: NavigationState = {}
if (this.props.openDrawer) {
newState.drawerContent = this.props.openDrawer
if (
Expand All @@ -77,7 +114,7 @@ class Navigation extends Component<any, State> {
}
}

onTransitionEnd() {
onTransitionEnd(): void {
if (this.transitionState === Closing) {
this.setState({
transitionState: Closed,
Expand All @@ -91,32 +128,37 @@ class Navigation extends Component<any, State> {
}
}

render() {
render(): JSX.Element {
const { onNavClick, topNavItems, bottomNavItems = [] } = this.props

const buildNavList = (list: any, selected: any) =>
list.map((item: any) => {
const buildNavList = (list: NavItem[], selected?: null | string) =>
list.map(item => {
const isOpen = item.name.toLowerCase() === selected
return (
<NavigationButtonContainer
title={item.title}
data-testid={'drawer' + item.name}
key={item.name}
onClick={() => onNavClick(item.name.toLowerCase())}
isOpen={isOpen}
>
<StyledNavigationButton name={item.name}>
{item.icon(isOpen)}
</StyledNavigationButton>
</NavigationButtonContainer>
<>
{item.enableCannyBadge ? (
<StyledCannyBadgeAnchor data-canny-changelog />
) : null}
<NavigationButtonContainer
title={item.title}
data-testid={'drawer' + item.name}
key={item.name}
onClick={() => onNavClick(item.name.toLowerCase())}
isOpen={isOpen}
>
<StyledNavigationButton name={item.name}>
{item.icon(isOpen)}
</StyledNavigationButton>
</NavigationButtonContainer>
</>
)
})

const getContentToShow = (openDrawer: any) => {
const getContentToShow = (openDrawer?: null | string) => {
if (openDrawer) {
const filteredList = topNavItems
.concat(bottomNavItems)
.filter((item: any) => item.name.toLowerCase() === openDrawer)
.filter(item => item.name.toLowerCase() === openDrawer)
const TabContent = filteredList[0].content
return <TabContent />
}
Expand Down
32 changes: 25 additions & 7 deletions src/browser/components/buttons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import { hexToRgba } from '../../styles/utils'

import styles from './style.css'

export const CloseButton = (props: any) => {
export const CloseButton = (props: any): JSX.Element => {
return <button {...props}>×</button>
}

export const EditorButton = (props: any) => {
export const EditorButton = (props: any): JSX.Element => {
const { icon, title, color, width, onClick, ...rest } = props
const overrideColor = { ...(color ? { color } : {}) }
return (
Expand Down Expand Up @@ -77,6 +77,24 @@ const BaseButton: any = styled.span`
}
`

export const StyledCannyBadgeAnchor = styled.div`
pointer-events: none;

.Canny_BadgeContainer {
pointer-events: none;

.Canny_Badge {
pointer-events: none;
top: 10px;
right: 10px;
border-radius: 10px;
background-color: red;
padding: 4px;
border: 1px solid red;
}
}
`

export const StyledNavigationButton = styled.button`
background: transparent;
border: 0;
Expand Down Expand Up @@ -229,7 +247,7 @@ interface ButtonTypeProps {
className?: any
}

export const FormButton = (props: ButtonTypeProps) => {
export const FormButton = (props: ButtonTypeProps): JSX.Element => {
const { icon, label, children, ...rest } = props
const ButtonType =
buttonTypes[props.buttonType as string] || buttonTypes.primary
Expand Down Expand Up @@ -262,7 +280,7 @@ export const FormButton = (props: ButtonTypeProps) => {
)
}

export const CypherFrameButton = (props: any) => {
export const CypherFrameButton = (props: any): JSX.Element => {
const { selected, ...rest } = props
return selected ? (
<StyledSelectedCypherFrameButton {...rest} />
Expand Down Expand Up @@ -296,7 +314,7 @@ const StyledSelectedCypherFrameButton = styled(StyledCypherFrameButton)`
color: ${props => props.theme.secondaryButtonTextHover};
fill: ${props => props.theme.secondaryButtonTextHover};
`
export const FrameButton = (props: any) => {
export const FrameButton = (props: any): JSX.Element => {
const { pressed, children, ...rest } = props
return pressed ? (
<StyledFrameButtonPressed {...rest}>{children}</StyledFrameButtonPressed>
Expand Down Expand Up @@ -361,7 +379,7 @@ export const FrameButtonAChild = styled(DefaultA)`
}
`

export const ActionButton = (props: any) => {
export const ActionButton = (props: any): JSX.Element => {
const { className, ...rest } = props
return <button className={className + ' ' + styles.action} {...rest} />
}
Expand Down Expand Up @@ -446,7 +464,7 @@ const BaseCarouselButton = styled.button`
}
`

export const CarouselButton = (props: any) => {
export const CarouselButton = (props: any): JSX.Element => {
const { children, ...rest } = props
return <BaseCarouselButton {...rest}>{children}</BaseCarouselButton>
}
Expand Down
Loading