}
style={{ minWidth: 25 }}
diff --git a/src/components/Dashboard/common/CursorTooltip.jsx b/src/components/Dashboard/common/CursorTooltip.jsx
new file mode 100644
index 00000000..cd353ca1
--- /dev/null
+++ b/src/components/Dashboard/common/CursorTooltip.jsx
@@ -0,0 +1,142 @@
+import { useCallback, useLayoutEffect, useRef, useState } from 'react'
+import { createPortal } from 'react-dom'
+import { Card } from 'antd'
+import PropTypes from 'prop-types'
+
+const OFFSET = 10
+
+const getTooltipRoot = () => {
+ let root = document.getElementById('cursor-tooltip-root')
+ if (!root) {
+ root = document.createElement('div')
+ root.id = 'cursor-tooltip-root'
+ document.documentElement.appendChild(root)
+ }
+ return root
+}
+
+const CursorTooltip = ({ content, pointRef }) => {
+ const tooltipRef = useRef(null)
+ const sizeRef = useRef({ width: 0, height: 0 })
+ const frameRef = useRef(null)
+ const contentRef = useRef(content)
+ const lastContentRef = useRef(content)
+ const [root, setRoot] = useState(null)
+
+ contentRef.current = content
+ if (content != null && content !== false && content !== '') {
+ lastContentRef.current = content
+ }
+
+ const applyPosition = useCallback(() => {
+ const el = tooltipRef.current
+ if (!el) return
+
+ const { width, height } = sizeRef.current
+ const { x, y } = pointRef.current
+ let left = x + OFFSET
+ let top = y + OFFSET
+ const maxLeft = window.innerWidth - width - OFFSET
+ const maxTop = window.innerHeight - height - OFFSET
+
+ if (width > 0 && left > maxLeft) left = Math.max(OFFSET, maxLeft)
+ if (height > 0 && top > maxTop) top = Math.max(OFFSET, maxTop)
+
+ el.style.transform = `translate3d(${left}px, ${top}px, 0)`
+ }, [pointRef])
+
+ const schedulePosition = useCallback(() => {
+ if (frameRef.current != null) return
+ frameRef.current = window.requestAnimationFrame(() => {
+ frameRef.current = null
+ applyPosition()
+ })
+ }, [applyPosition])
+
+ useLayoutEffect(() => {
+ setRoot(getTooltipRoot())
+ }, [])
+
+ useLayoutEffect(() => {
+ applyPosition()
+ }, [applyPosition, content])
+
+ useLayoutEffect(() => {
+ const el = tooltipRef.current
+ if (!el) return
+
+ const updateSize = () => {
+ sizeRef.current = {
+ width: el.offsetWidth,
+ height: el.offsetHeight
+ }
+ applyPosition()
+ }
+
+ updateSize()
+ const observer = new ResizeObserver(updateSize)
+ observer.observe(el)
+
+ const onMove = () => {
+ const next = contentRef.current
+ if (next == null || next === false || next === '') return
+ schedulePosition()
+ }
+
+ window.addEventListener('mousemove', onMove, { passive: true })
+ return () => {
+ observer.disconnect()
+ window.removeEventListener('mousemove', onMove)
+ if (frameRef.current != null) {
+ window.cancelAnimationFrame(frameRef.current)
+ frameRef.current = null
+ }
+ }
+ }, [applyPosition, root, schedulePosition])
+
+ const visible = content != null && content !== false && content !== ''
+
+ if (!root) return null
+
+ return createPortal(
+
+
+ {lastContentRef.current}
+
+
,
+ root
+ )
+}
+
+CursorTooltip.propTypes = {
+ content: PropTypes.node,
+ pointRef: PropTypes.shape({
+ current: PropTypes.shape({
+ x: PropTypes.number,
+ y: PropTypes.number
+ })
+ }).isRequired
+}
+
+export default CursorTooltip
diff --git a/src/components/Dashboard/common/DashboardNavigation.jsx b/src/components/Dashboard/common/DashboardNavigation.jsx
index ef4b7653..7a1e5636 100644
--- a/src/components/Dashboard/common/DashboardNavigation.jsx
+++ b/src/components/Dashboard/common/DashboardNavigation.jsx
@@ -6,7 +6,6 @@ import {
Tag,
Space,
Button,
- Tooltip,
Badge,
Divider,
Typography,
@@ -17,6 +16,7 @@ import { AuthContext } from '../context/AuthContext'
import { SpotlightContext } from '../context/SpotlightContext'
import { ApiServerContext } from '../context/ApiServerContext'
import { NotificationContext } from '../context/NotificationContext'
+import Tooltip from './Tooltip'
import { useNavigate, useLocation } from 'react-router-dom'
import { Header } from 'antd/es/layout/layout'
import { useMediaQuery } from 'react-responsive'
@@ -43,7 +43,8 @@ import WindowAppMenu from './WindowAppMenu'
import WebAppSwitcher from './WebAppSwitcher'
import {
getSidebarDefaultPath,
- getSidebarMenuSections
+ getSidebarMenuSections,
+ isSidebarSectionVisible
} from '../../../database/Sidebars'
import { useAppUpdateContext } from '../context/AppUpdateContext'
@@ -75,40 +76,44 @@ const DashboardNavigation = () => {
isMaximized
} = useContext(ElectronContext)
const { availableUpdate, checkForUpdates } = useAppUpdateContext()
+ const includeDev = import.meta.env.DEV
const mainMenuItems = useMemo(
- () => [
- {
- key: 'production',
- label: 'Production',
- className: 'electrobun-webkit-app-region-no-drag',
- icon:
- },
- {
- key: 'inventory',
- label: 'Inventory',
- className: 'electrobun-webkit-app-region-no-drag',
- icon:
- },
- {
- key: 'sales',
- label: 'Sales',
- className: 'electrobun-webkit-app-region-no-drag',
- icon:
- },
- {
- key: 'finance',
- label: 'Finance',
- className: 'electrobun-webkit-app-region-no-drag',
- icon:
- },
- {
- key: 'management',
- label: 'Management',
- className: 'electrobun-webkit-app-region-no-drag',
- icon:
- }
- ],
- []
+ () =>
+ [
+ {
+ key: 'production',
+ label: 'Production',
+ className: 'electrobun-webkit-app-region-no-drag',
+ icon:
+ },
+ {
+ key: 'inventory',
+ label: 'Inventory',
+ className: 'electrobun-webkit-app-region-no-drag',
+ icon:
+ },
+ {
+ key: 'sales',
+ label: 'Sales',
+ className: 'electrobun-webkit-app-region-no-drag',
+ icon:
+ },
+ {
+ key: 'finance',
+ label: 'Finance',
+ className: 'electrobun-webkit-app-region-no-drag',
+ icon:
+ },
+ {
+ key: 'management',
+ label: 'Management',
+ className: 'electrobun-webkit-app-region-no-drag',
+ icon:
+ }
+ ].filter((item) =>
+ isSidebarSectionVisible(item.key, { includeDev, userProfile })
+ ),
+ [includeDev, userProfile]
)
const [userPopoverOpen, setUserPopoverOpen] = useState(false)
@@ -120,10 +125,13 @@ const DashboardNavigation = () => {
useEffect(() => {
const pathParts = location.pathname.split('/').filter(Boolean)
if (pathParts.length > 2) {
- setSelectedMenuItem(
- mainMenuItems.filter((item) => item.key == pathParts[1])[0]
- )
- setSelectedKey(pathParts[1]) // Return the section (production/management)
+ const nextItem =
+ mainMenuItems.find((item) => item.key == pathParts[1]) ||
+ mainMenuItems[0]
+ if (nextItem) {
+ setSelectedMenuItem(nextItem)
+ setSelectedKey(nextItem.key)
+ }
}
}, [location.pathname, mainMenuItems])
@@ -138,15 +146,14 @@ const DashboardNavigation = () => {
}, [connecting, connected])
const handleMainMenuClick = ({ key }) => {
- navigate(getSidebarDefaultPath(key, { includeDev: import.meta.env.DEV }))
+ navigate(getSidebarDefaultPath(key, { includeDev, userProfile }))
}
useEffect(() => {
if (!isElectron || !setSidebarViewMenu) return
- const includeDev = import.meta.env.DEV
- const sections = getSidebarMenuSections({ includeDev })
+ const sections = getSidebarMenuSections({ includeDev, userProfile })
setSidebarViewMenu(sections)
- }, [isElectron, setSidebarViewMenu])
+ }, [includeDev, isElectron, setSidebarViewMenu, userProfile])
const isMacOSApp = isElectron && platform == 'darwin'
const isOtherApp = isElectron && platform != 'darwin'
@@ -194,7 +201,7 @@ const DashboardNavigation = () => {
maxWidth: '100%' // responsive
}}
>
- {selectedMenuItem.icon}
+ {selectedMenuItem?.icon}
{
flex: 1
}}
>
- {selectedMenuItem.label}
+ {selectedMenuItem?.label}
)}
@@ -292,7 +299,7 @@ const DashboardNavigation = () => {
{import.meta.env.MODE === 'development' && (
{apiServerState === 'connected' ? (
-
+
{
) : null}
{apiServerState === 'connecting' ? (
-
+
{
) : null}
{apiServerState === 'disconnected' ? (
-
+
{
/>
) : null}
-
+
{
if (typeof collapsedProp === 'boolean') {
@@ -69,7 +73,7 @@ const DashboardSidebar = ({
}
// Map items recursively
- const _items = mapItemsRecursively(items)
+ const _items = mapItemsRecursively(allowedItems)
if (isMobile) {
return (
diff --git a/src/components/Dashboard/common/EmailDisplay.jsx b/src/components/Dashboard/common/EmailDisplay.jsx
index 60550649..0e71e432 100644
--- a/src/components/Dashboard/common/EmailDisplay.jsx
+++ b/src/components/Dashboard/common/EmailDisplay.jsx
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types'
-import { Typography, Flex, Button, Tooltip } from 'antd'
+import { Typography, Flex, Button } from 'antd'
+import Tooltip from './Tooltip'
import NewMailIcon from '../../Icons/NewMailIcon'
// import CopyIcon from './CopyIcon'
import CopyButton from './CopyButton'
@@ -22,7 +23,7 @@ const EmailDisplay = ({ email, showCopy = true, showLink = false }) => {
{email}
-
+
}
type='text'
diff --git a/src/components/Dashboard/common/MarkdownToolbar.jsx b/src/components/Dashboard/common/MarkdownToolbar.jsx
index dd0b93b2..82665492 100644
--- a/src/components/Dashboard/common/MarkdownToolbar.jsx
+++ b/src/components/Dashboard/common/MarkdownToolbar.jsx
@@ -9,10 +9,10 @@ import {
Input,
Popover,
Select,
- Space,
- Tooltip
+ Space
} from 'antd'
import PropTypes from 'prop-types'
+import Tooltip from './Tooltip'
import BlockquoteIcon from '../../Icons/BlockquoteIcon'
import BoldIcon from '../../Icons/BoldIcon'
import BulletListIcon from '../../Icons/BulletListIcon'
@@ -199,7 +199,7 @@ const MarkdownToolbar = ({
disabled={!editor || editingToolsDisabled}
/>
-
+
-
+
-
+
-
+
-
+
-
+