Add observability for LLM topic context inclusion (#1038)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomasnordquist <7721625+thomasnordquist@users.noreply.github.com> Co-authored-by: Thomas Nordquist <thomasnordquist@users.noreply.github.com>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import * as React from 'react'
|
||||
import ChartPanel from '../ChartPanel'
|
||||
import ReactSplitPaneImport from 'react-split-pane'
|
||||
import { connect } from 'react-redux'
|
||||
import { List } from 'immutable'
|
||||
import { useResizeDetector } from 'react-resize-detector'
|
||||
import ChartPanel from '../ChartPanel'
|
||||
import Tree from '../Tree'
|
||||
import { AppState } from '../../reducers'
|
||||
import { ChartParameters } from '../../reducers/Charts'
|
||||
import { connect } from 'react-redux'
|
||||
import { List } from 'immutable'
|
||||
import { Sidebar } from '../Sidebar'
|
||||
import { useResizeDetector } from 'react-resize-detector'
|
||||
import MobileTabs from './MobileTabs'
|
||||
import PublishTab from '../Sidebar/PublishTab'
|
||||
|
||||
@@ -30,31 +30,31 @@ function ContentView(props: Props) {
|
||||
const [sidebarWidth, setSidebarWidth] = React.useState<string | number>(isMobile ? '100%' : '40%')
|
||||
const [detectedHeight, setDetectedHeight] = React.useState(0)
|
||||
const [detectedSidebarWidth, setDetectedSidebarWidth] = React.useState(0)
|
||||
|
||||
|
||||
// Update mobile state on resize
|
||||
React.useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setIsMobile(window.innerWidth <= 768)
|
||||
}
|
||||
|
||||
|
||||
// Set initial state
|
||||
handleResize()
|
||||
|
||||
|
||||
window.addEventListener('resize', handleResize)
|
||||
return () => window.removeEventListener('resize', handleResize)
|
||||
}, [])
|
||||
|
||||
|
||||
const { height: resizeHeight, ref: heightRef } = useResizeDetector()
|
||||
const { width: resizeWidth, ref: widthRef } = useResizeDetector()
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
if (resizeHeight) setDetectedHeight(resizeHeight)
|
||||
}, [resizeHeight])
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
if (resizeWidth) setDetectedSidebarWidth(resizeWidth)
|
||||
}, [resizeWidth])
|
||||
|
||||
|
||||
const detectSize = React.useCallback((width: any, newHeight: any) => {
|
||||
setDetectedHeight(newHeight)
|
||||
}, [])
|
||||
@@ -92,8 +92,8 @@ function ContentView(props: Props) {
|
||||
// Expose tab switching functions for other components to call
|
||||
React.useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).switchToDetailsTab = () => setMobileTab(1)
|
||||
(window as any).switchToTopicsTab = () => setMobileTab(0)
|
||||
;(window as any).switchToDetailsTab = () =>
|
||||
(setMobileTab(1)(window as any).switchToTopicsTab = () => setMobileTab(0))
|
||||
;(window as any).switchToPublishTab = () => setMobileTab(2)
|
||||
;(window as any).switchToChartsTab = () => setMobileTab(3)
|
||||
}
|
||||
@@ -107,6 +107,19 @@ function ContentView(props: Props) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Scroll to selected topic when returning to tree tab
|
||||
React.useEffect(() => {
|
||||
if (mobileTab === 0) {
|
||||
// Delay to ensure DOM is rendered
|
||||
setTimeout(() => {
|
||||
const selectedNode = document.querySelector('.tree .selected')
|
||||
if (selectedNode) {
|
||||
selectedNode.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
}, [mobileTab])
|
||||
|
||||
const mobileContainerStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@@ -150,30 +163,22 @@ function ContentView(props: Props) {
|
||||
<div style={mobileContainerStyle}>
|
||||
<MobileTabs value={mobileTab} onChange={setMobileTab} />
|
||||
<div style={tabContentStyle}>
|
||||
{/* Topics tab */}
|
||||
{mobileTab === 0 && (
|
||||
<div style={treeContainerStyle}>
|
||||
<Tree />
|
||||
</div>
|
||||
)}
|
||||
{/* Details tab */}
|
||||
{mobileTab === 1 && (
|
||||
<div style={sidebarContainerStyle}>
|
||||
<Sidebar connectionId={props.connectionId} />
|
||||
</div>
|
||||
)}
|
||||
{/* Publish tab */}
|
||||
{mobileTab === 2 && (
|
||||
<div style={sidebarContainerStyle}>
|
||||
<PublishTab connectionId={props.connectionId} />
|
||||
</div>
|
||||
)}
|
||||
{/* Charts tab */}
|
||||
{mobileTab === 3 && (
|
||||
<div style={sidebarContainerStyle}>
|
||||
<ChartPanel />
|
||||
</div>
|
||||
)}
|
||||
{/* Topics tab - keep mounted, toggle visibility */}
|
||||
<div style={{ ...treeContainerStyle, display: mobileTab === 0 ? 'block' : 'none' }}>
|
||||
<Tree />
|
||||
</div>
|
||||
{/* Details tab - keep mounted, toggle visibility */}
|
||||
<div style={{ ...sidebarContainerStyle, display: mobileTab === 1 ? 'block' : 'none' }}>
|
||||
<Sidebar connectionId={props.connectionId} />
|
||||
</div>
|
||||
{/* Publish tab - keep mounted, toggle visibility */}
|
||||
<div style={{ ...sidebarContainerStyle, display: mobileTab === 2 ? 'block' : 'none' }}>
|
||||
<PublishTab connectionId={props.connectionId} />
|
||||
</div>
|
||||
{/* Charts tab - keep mounted, toggle visibility */}
|
||||
<div style={{ ...sidebarContainerStyle, display: mobileTab === 3 ? 'block' : 'none' }}>
|
||||
<ChartPanel />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -192,7 +197,7 @@ function ContentView(props: Props) {
|
||||
size={sidebarWidth}
|
||||
onChange={(size: number) => setSidebarWidth(size)}
|
||||
onDragFinished={closeSidebarCompletelyIfItSitsOnTheEdge}
|
||||
allowResize={true}
|
||||
allowResize
|
||||
style={{ height: '100%' }}
|
||||
pane1Style={{ overflowX: 'hidden' }}
|
||||
resizerStyle={{ height: '100%' }}
|
||||
@@ -203,7 +208,7 @@ function ContentView(props: Props) {
|
||||
split="horizontal"
|
||||
minSize={0}
|
||||
size={height}
|
||||
allowResize={true}
|
||||
allowResize
|
||||
style={{ height: 'calc(100vh - 64px)' }}
|
||||
pane1Style={{ maxHeight: '100%' }}
|
||||
pane2Style={{ borderTop: '1px solid #999', display: 'flex' }}
|
||||
@@ -212,7 +217,15 @@ function ContentView(props: Props) {
|
||||
>
|
||||
<Tree />
|
||||
{/** Passing height constraints via flex options down */}
|
||||
<div ref={heightRef} style={{ flex: 1, display: 'flex', height: '100%', width: '100%' }}>
|
||||
<div
|
||||
ref={heightRef}
|
||||
style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{/** Resize detector must not be in the scroll zone, it needs to detect actual available size */}
|
||||
<ChartPanel />
|
||||
</div>
|
||||
@@ -221,11 +234,11 @@ function ContentView(props: Props) {
|
||||
<div ref={widthRef} style={{ height: '100%' }}>
|
||||
<div
|
||||
className={props.paneDefaults}
|
||||
style={{
|
||||
minWidth: '250px',
|
||||
height: '100%',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden'
|
||||
style={{
|
||||
minWidth: '250px',
|
||||
height: '100%',
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Sidebar connectionId={props.connectionId} />
|
||||
@@ -237,10 +250,8 @@ function ContentView(props: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
chartPanelItems: state.charts.get('charts'),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
chartPanelItems: state.charts.get('charts'),
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps)(ContentView)
|
||||
|
||||
@@ -20,41 +20,41 @@ function MobileTabs(props: Props) {
|
||||
|
||||
return (
|
||||
<Box className={props.classes.root} role="navigation" aria-label="Mobile navigation tabs">
|
||||
<Tabs
|
||||
value={props.value}
|
||||
<Tabs
|
||||
value={props.value}
|
||||
onChange={handleChange}
|
||||
variant="fullWidth"
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
aria-label="Topics, Details, Publish and Charts tabs"
|
||||
>
|
||||
<Tab
|
||||
<Tab
|
||||
icon={<AccountTreeIcon />}
|
||||
label="Topics"
|
||||
label="Topics"
|
||||
data-testid="mobile-tab-topics"
|
||||
aria-label="View topics tree"
|
||||
id="mobile-tab-0"
|
||||
aria-controls="mobile-tabpanel-0"
|
||||
/>
|
||||
<Tab
|
||||
<Tab
|
||||
icon={<InfoIcon />}
|
||||
label="Details"
|
||||
label="Details"
|
||||
data-testid="mobile-tab-details"
|
||||
aria-label="View topic details"
|
||||
id="mobile-tab-1"
|
||||
aria-controls="mobile-tabpanel-1"
|
||||
/>
|
||||
<Tab
|
||||
<Tab
|
||||
icon={<SendIcon />}
|
||||
label="Publish"
|
||||
label="Publish"
|
||||
data-testid="mobile-tab-publish"
|
||||
aria-label="Publish messages"
|
||||
id="mobile-tab-2"
|
||||
aria-controls="mobile-tabpanel-2"
|
||||
/>
|
||||
<Tab
|
||||
<Tab
|
||||
icon={<ShowChartIcon />}
|
||||
label="Charts"
|
||||
label="Charts"
|
||||
data-testid="mobile-tab-charts"
|
||||
aria-label="View charts"
|
||||
id="mobile-tab-3"
|
||||
@@ -69,7 +69,7 @@ const styles = (theme: Theme) => ({
|
||||
root: {
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
position: 'relative' as 'relative',
|
||||
position: 'relative' as const,
|
||||
zIndex: 1,
|
||||
minHeight: '56px', // Touch-friendly tab height
|
||||
'& .MuiTab-root': {
|
||||
@@ -77,7 +77,7 @@ const styles = (theme: Theme) => ({
|
||||
fontSize: '16px', // Prevent iOS zoom
|
||||
fontWeight: 500,
|
||||
padding: theme.spacing(1.5, 2),
|
||||
textTransform: 'none' as 'none', // Better readability
|
||||
textTransform: 'none' as const, // Better readability
|
||||
'&:active': {
|
||||
opacity: 0.7, // Touch feedback
|
||||
},
|
||||
|
||||
@@ -30,8 +30,8 @@ class Notification extends React.PureComponent<Props, {}> {
|
||||
|
||||
public render() {
|
||||
const snackbarAnchor = {
|
||||
vertical: 'bottom' as 'bottom',
|
||||
horizontal: 'left' as 'left',
|
||||
vertical: 'bottom' as const,
|
||||
horizontal: 'left' as const,
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as React from 'react'
|
||||
import * as q from '../../../../backend/src/Model'
|
||||
import CustomIconButton from '../helper/CustomIconButton'
|
||||
import Pause from '@mui/icons-material/PauseCircleFilled'
|
||||
import Resume from '@mui/icons-material/PlayArrow'
|
||||
import { AppState } from '../../reducers'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { connect } from 'react-redux'
|
||||
import { treeActions } from '../../actions'
|
||||
import { withStyles } from '@mui/styles'
|
||||
import { Theme } from '@mui/material/styles'
|
||||
import * as q from '../../../../backend/src/Model'
|
||||
import CustomIconButton from '../helper/CustomIconButton'
|
||||
import { treeActions } from '../../actions'
|
||||
import { AppState } from '../../reducers'
|
||||
|
||||
const styles = (theme: Theme) => ({
|
||||
icon: {
|
||||
color: theme.palette.primary.contrastText,
|
||||
verticalAlign: 'middle' as 'middle',
|
||||
verticalAlign: 'middle' as const,
|
||||
},
|
||||
bufferStats: {
|
||||
minWidth: '8em',
|
||||
@@ -31,6 +31,7 @@ interface Props {
|
||||
|
||||
class PauseButton extends React.PureComponent<Props, { changes: number }> {
|
||||
private timer?: any
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = { changes: 0 }
|
||||
@@ -88,19 +89,15 @@ class PauseButton extends React.PureComponent<Props, { changes: number }> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
paused: state.tree.get('paused'),
|
||||
tree: state.tree.get('tree'),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
paused: state.tree.get('paused'),
|
||||
tree: state.tree.get('tree'),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
return {
|
||||
actions: {
|
||||
tree: bindActionCreators(treeActions, dispatch),
|
||||
},
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
actions: {
|
||||
tree: bindActionCreators(treeActions, dispatch),
|
||||
},
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PauseButton) as any)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React, { useCallback, useState, useRef } from 'react'
|
||||
import ClearAdornment from '../helper/ClearAdornment'
|
||||
import Search from '@mui/icons-material/Search'
|
||||
import { AppState } from '../../reducers'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { connect } from 'react-redux'
|
||||
import { InputBase } from '@mui/material'
|
||||
import { settingsActions } from '../../actions'
|
||||
import { alpha as fade, Theme } from '@mui/material/styles'
|
||||
import { withStyles } from '@mui/styles'
|
||||
import { settingsActions } from '../../actions'
|
||||
import { AppState } from '../../reducers'
|
||||
import ClearAdornment from '../helper/ClearAdornment'
|
||||
import { useGlobalKeyEventHandler } from '../../effects/useGlobalKeyEventHandler'
|
||||
import { KeyCodes } from '../../utils/KeyCodes'
|
||||
|
||||
@@ -28,7 +28,7 @@ function SearchBar(props: {
|
||||
// On mobile, switch to Topics tab when search is focused
|
||||
if (typeof window !== 'undefined' && window.innerWidth <= 768) {
|
||||
if ((window as any).switchToTopicsTab) {
|
||||
(window as any).switchToTopicsTab()
|
||||
;(window as any).switchToTopicsTab()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
@@ -90,24 +90,20 @@ function SearchBar(props: {
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
topicFilter: state.settings.get('topicFilter'),
|
||||
hasConnection: Boolean(state.connection.connectionId),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
topicFilter: state.settings.get('topicFilter'),
|
||||
hasConnection: Boolean(state.connection.connectionId),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
return {
|
||||
actions: {
|
||||
settings: bindActionCreators(settingsActions, dispatch),
|
||||
},
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
actions: {
|
||||
settings: bindActionCreators(settingsActions, dispatch),
|
||||
},
|
||||
})
|
||||
|
||||
const styles = (theme: Theme) => ({
|
||||
search: {
|
||||
position: 'relative' as 'relative',
|
||||
position: 'relative' as const,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: fade(theme.palette.common.white, 0.15),
|
||||
'&:hover': {
|
||||
@@ -122,21 +118,21 @@ const styles = (theme: Theme) => ({
|
||||
maxWidth: '30%',
|
||||
|
||||
marginLeft: theme.spacing(4),
|
||||
width: 'auto' as 'auto',
|
||||
width: 'auto' as const,
|
||||
},
|
||||
[theme.breakpoints.up(750)]: {
|
||||
marginLeft: theme.spacing(4),
|
||||
width: 'auto' as 'auto',
|
||||
width: 'auto' as const,
|
||||
},
|
||||
},
|
||||
searchIcon: {
|
||||
width: theme.spacing(6),
|
||||
height: '100%',
|
||||
position: 'absolute' as 'absolute',
|
||||
pointerEvents: 'none' as 'none',
|
||||
display: 'flex' as 'flex',
|
||||
alignItems: 'center' as 'center',
|
||||
justifyContent: 'center' as 'center',
|
||||
position: 'absolute' as const,
|
||||
pointerEvents: 'none' as const,
|
||||
display: 'flex' as const,
|
||||
alignItems: 'center' as const,
|
||||
justifyContent: 'center' as const,
|
||||
},
|
||||
inputRoot: {
|
||||
color: `${theme.palette.common.white} !important`, // Ensure white text color with high specificity
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
import * as React from 'react'
|
||||
import CloudOff from '@mui/icons-material/CloudOff'
|
||||
import Logout from '@mui/icons-material/Logout'
|
||||
import ConnectionHealthIndicator from '../helper/ConnectionHealthIndicator'
|
||||
const ConnectionHealthIndicatorAny = ConnectionHealthIndicator as any
|
||||
import Menu from '@mui/icons-material/Menu'
|
||||
import PauseButton from './PauseButton'
|
||||
import SearchBar from './SearchBar'
|
||||
import { AppBar, Button, IconButton, Toolbar, Typography } from '@mui/material'
|
||||
import { AppState } from '../../reducers'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { connect } from 'react-redux'
|
||||
import { connectionActions, globalActions, settingsActions } from '../../actions'
|
||||
import { Theme } from '@mui/material/styles'
|
||||
import { withStyles } from '@mui/styles'
|
||||
import { connectionActions, globalActions, settingsActions } from '../../actions'
|
||||
import { AppState } from '../../reducers'
|
||||
import SearchBar from './SearchBar'
|
||||
import PauseButton from './PauseButton'
|
||||
import ConnectionHealthIndicator from '../helper/ConnectionHealthIndicator'
|
||||
import { isBrowserMode } from '../../utils/browserMode'
|
||||
import { useAuth } from '../../contexts/AuthContext'
|
||||
|
||||
const ConnectionHealthIndicatorAny = ConnectionHealthIndicator as any
|
||||
|
||||
const styles = (theme: Theme) => ({
|
||||
title: {
|
||||
display: 'none' as 'none',
|
||||
display: 'none' as const,
|
||||
[theme.breakpoints.up(750)]: {
|
||||
display: 'block' as 'block',
|
||||
display: 'block' as const,
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'block' as 'block',
|
||||
display: 'block' as const,
|
||||
},
|
||||
whiteSpace: 'nowrap' as 'nowrap',
|
||||
whiteSpace: 'nowrap' as const,
|
||||
},
|
||||
disconnectIcon: {
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none' as 'none',
|
||||
display: 'none' as const,
|
||||
},
|
||||
marginRight: '8px',
|
||||
paddingLeft: '8px',
|
||||
@@ -42,14 +43,14 @@ const styles = (theme: Theme) => ({
|
||||
margin: 'auto 8px auto auto',
|
||||
// Hide on mobile (<=768px)
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none' as 'none',
|
||||
display: 'none' as const,
|
||||
},
|
||||
},
|
||||
logout: {
|
||||
margin: 'auto 0 auto 8px',
|
||||
// Hide on mobile (<=768px)
|
||||
[theme.breakpoints.down('md')]: {
|
||||
display: 'none' as 'none',
|
||||
display: 'none' as const,
|
||||
},
|
||||
},
|
||||
disconnectLabel: {
|
||||
@@ -76,13 +77,13 @@ class TitleBar extends React.PureComponent<Props, {}> {
|
||||
private handleLogout = async () => {
|
||||
// Disconnect first
|
||||
this.props.actions.connection.disconnect()
|
||||
|
||||
|
||||
// Clear credentials from sessionStorage
|
||||
if (typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.removeItem('mqtt-explorer-username')
|
||||
sessionStorage.removeItem('mqtt-explorer-password')
|
||||
}
|
||||
|
||||
|
||||
// Reload page to reset all state and show login dialog
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.reload()
|
||||
@@ -117,7 +118,7 @@ class TitleBar extends React.PureComponent<Props, {}> {
|
||||
Disconnect <CloudOff className={classes.disconnectIcon} />
|
||||
</Button>
|
||||
<LogoutButton classes={classes} onLogout={this.handleLogout} />
|
||||
<ConnectionHealthIndicatorAny withBackground={true} />
|
||||
<ConnectionHealthIndicatorAny withBackground />
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
)
|
||||
@@ -127,36 +128,28 @@ class TitleBar extends React.PureComponent<Props, {}> {
|
||||
// Separate component to use hooks
|
||||
function LogoutButton({ classes, onLogout }: { classes: any; onLogout: () => void }) {
|
||||
const { authDisabled } = useAuth()
|
||||
|
||||
|
||||
if (!isBrowserMode || authDisabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={classes.logout}
|
||||
sx={{ color: 'primary.contrastText' }}
|
||||
onClick={onLogout}
|
||||
>
|
||||
<Button className={classes.logout} sx={{ color: 'primary.contrastText' }} onClick={onLogout}>
|
||||
Logout <Logout className={classes.disconnectIcon} />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
topicFilter: state.settings.get('topicFilter'),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
topicFilter: state.settings.get('topicFilter'),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
return {
|
||||
actions: {
|
||||
settings: bindActionCreators(settingsActions, dispatch),
|
||||
global: bindActionCreators(globalActions, dispatch),
|
||||
connection: bindActionCreators(connectionActions, dispatch),
|
||||
},
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch: any) => ({
|
||||
actions: {
|
||||
settings: bindActionCreators(settingsActions, dispatch),
|
||||
global: bindActionCreators(globalActions, dispatch),
|
||||
connection: bindActionCreators(connectionActions, dispatch),
|
||||
},
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(TitleBar))
|
||||
|
||||
Reference in New Issue
Block a user