Skip to content

Commit

Permalink
Merge pull request #1282 from HerrEmil/canny
Browse files Browse the repository at this point in the history
Canny Support
  • Loading branch information
HerrEmil authored Feb 22, 2021
2 parents ce1c2cf + bdc6c83 commit 5800cce
Show file tree
Hide file tree
Showing 18 changed files with 628 additions and 278 deletions.
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

0 comments on commit 5800cce

Please sign in to comment.