Enhance Dashboard Navigation with Object Navigation Hook
- Introduced `useObjectNavigationTabPage` hook to streamline navigation tab management for various dashboard components, improving consistency in object handling. - Updated multiple components (DocumentTemplateDesign, EmailTemplateDesign, NoteInfo, GCodeFilePreview, ControlPrinter) to utilize the new hook for better object navigation and state management. - Adjusted CSS styles for dashboard tabs to improve layout and responsiveness, enhancing user experience across devices.
This commit is contained in:
parent
2f9f42c9e2
commit
7fef25d911
@ -3371,7 +3371,7 @@ body.objectKanbanColumnResizing * {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-tabs-label {
|
.dashboard-tabs-label {
|
||||||
max-width: 200px;
|
max-width: 280px;
|
||||||
margin-top: -2px;
|
margin-top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { useDashboardObjectTools } from '../../context/DashboardObjectToolsConte
|
|||||||
import ScrollBox from '../../common/ScrollBox.jsx'
|
import ScrollBox from '../../common/ScrollBox.jsx'
|
||||||
|
|
||||||
import TemplateEditor from '../../common/TemplateEditor.jsx'
|
import TemplateEditor from '../../common/TemplateEditor.jsx'
|
||||||
|
import { useObjectNavigationTabPage } from '../../hooks/useObjectNavigationTabPage'
|
||||||
|
|
||||||
const log = loglevel.getLogger('DocumentTemplateDesign')
|
const log = loglevel.getLogger('DocumentTemplateDesign')
|
||||||
log.setLevel(config.logLevel)
|
log.setLevel(config.logLevel)
|
||||||
@ -30,6 +31,11 @@ const DocumentTemplateDesign = () => {
|
|||||||
const documentTemplateId = new URLSearchParams(location.search).get(
|
const documentTemplateId = new URLSearchParams(location.search).get(
|
||||||
'documentTemplateId'
|
'documentTemplateId'
|
||||||
)
|
)
|
||||||
|
useObjectNavigationTabPage({
|
||||||
|
modelName: 'documentTemplate',
|
||||||
|
pageName: 'design',
|
||||||
|
objectId: documentTemplateId
|
||||||
|
})
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
'DocumentTemplateDesign',
|
'DocumentTemplateDesign',
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import ObjectActions from '../../common/ObjectActions'
|
|||||||
import TemplateEditor from '../../common/TemplateEditor'
|
import TemplateEditor from '../../common/TemplateEditor'
|
||||||
import ScrollBox from '../../common/ScrollBox'
|
import ScrollBox from '../../common/ScrollBox'
|
||||||
import { useDashboardObjectTools } from '../../context/DashboardObjectToolsContext'
|
import { useDashboardObjectTools } from '../../context/DashboardObjectToolsContext'
|
||||||
|
import { useObjectNavigationTabPage } from '../../hooks/useObjectNavigationTabPage'
|
||||||
|
|
||||||
const EmailTemplateDesign = () => {
|
const EmailTemplateDesign = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@ -24,6 +25,11 @@ const EmailTemplateDesign = () => {
|
|||||||
const emailTemplateId = new URLSearchParams(location.search).get(
|
const emailTemplateId = new URLSearchParams(location.search).get(
|
||||||
'emailTemplateId'
|
'emailTemplateId'
|
||||||
)
|
)
|
||||||
|
useObjectNavigationTabPage({
|
||||||
|
modelName: 'emailTemplate',
|
||||||
|
pageName: 'design',
|
||||||
|
objectId: emailTemplateId
|
||||||
|
})
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
'EmailTemplateDesign',
|
'EmailTemplateDesign',
|
||||||
{ preview: true, editor: true, notes: true }
|
{ preview: true, editor: true, notes: true }
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import ActivityIndicator from '../../common/ActivityIndicator.jsx'
|
|||||||
import ActionHandler from '../../common/ActionHandler.jsx'
|
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||||
import { useDashboardObjectTools } from '../../context/DashboardObjectToolsContext'
|
import { useDashboardObjectTools } from '../../context/DashboardObjectToolsContext'
|
||||||
import { useNavigationTabPage } from '../../context/NavigationTabsContext'
|
import { useObjectNavigationTabPage } from '../../hooks/useObjectNavigationTabPage'
|
||||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||||
import InfoActionButtons from '../../common/InfoActionButtons.jsx'
|
import InfoActionButtons from '../../common/InfoActionButtons.jsx'
|
||||||
@ -33,11 +33,15 @@ const log = loglevel.getLogger('NoteInfo')
|
|||||||
log.setLevel(config.logLevel)
|
log.setLevel(config.logLevel)
|
||||||
|
|
||||||
const NoteInfo = () => {
|
const NoteInfo = () => {
|
||||||
useNavigationTabPage({ title: 'Info - Note', modelName: 'note' })
|
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const objectFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const noteId = new URLSearchParams(location.search).get('noteId')
|
const noteId = new URLSearchParams(location.search).get('noteId')
|
||||||
|
useObjectNavigationTabPage({
|
||||||
|
modelName: 'note',
|
||||||
|
pageName: 'info',
|
||||||
|
objectId: noteId
|
||||||
|
})
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('NoteInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('NoteInfo', {
|
||||||
info: true,
|
info: true,
|
||||||
content: true,
|
content: true,
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import MissingPlaceholder from '../../common/MissingPlaceholder.jsx'
|
|||||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||||
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
|
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
|
||||||
|
import { useObjectNavigationTabPage } from '../../hooks/useObjectNavigationTabPage'
|
||||||
|
|
||||||
const log = loglevel.getLogger('GCodeFilePreview')
|
const log = loglevel.getLogger('GCodeFilePreview')
|
||||||
log.setLevel(config.logLevel)
|
log.setLevel(config.logLevel)
|
||||||
@ -29,6 +30,11 @@ const GCodeFilePreview = () => {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const objectFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
|
const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
|
||||||
|
useObjectNavigationTabPage({
|
||||||
|
modelName: 'gcodeFile',
|
||||||
|
pageName: 'preview',
|
||||||
|
objectId: gcodeFileId
|
||||||
|
})
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
'GCodeFilePreview',
|
'GCodeFilePreview',
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButt
|
|||||||
import PrinterControlButtons from '../../common/PrinterControlButtons.jsx'
|
import PrinterControlButtons from '../../common/PrinterControlButtons.jsx'
|
||||||
import PrinterQueue from '../../common/PrinterQueue.jsx'
|
import PrinterQueue from '../../common/PrinterQueue.jsx'
|
||||||
import ListIcon from '../../../Icons/ListIcon.jsx'
|
import ListIcon from '../../../Icons/ListIcon.jsx'
|
||||||
|
import { useObjectNavigationTabPage } from '../../hooks/useObjectNavigationTabPage'
|
||||||
|
|
||||||
const log = loglevel.getLogger('ControlPrinter')
|
const log = loglevel.getLogger('ControlPrinter')
|
||||||
log.setLevel(config.logLevel)
|
log.setLevel(config.logLevel)
|
||||||
@ -47,6 +48,11 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
|
|||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||||
const printerId = new URLSearchParams(location.search).get('printerId')
|
const printerId = new URLSearchParams(location.search).get('printerId')
|
||||||
|
useObjectNavigationTabPage({
|
||||||
|
modelName: 'printer',
|
||||||
|
pageName: 'control',
|
||||||
|
objectId: printerId
|
||||||
|
})
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
'ControlPrinter',
|
'ControlPrinter',
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const { Text } = Typography
|
|||||||
|
|
||||||
const DashboardTabLabel = ({ tab, onClose }) => (
|
const DashboardTabLabel = ({ tab, onClose }) => (
|
||||||
<Flex align='center' gap={6} className='dashboard-tabs-label'>
|
<Flex align='center' gap={6} className='dashboard-tabs-label'>
|
||||||
<Text ellipsis style={{ maxWidth: 160 }}>
|
<Text ellipsis style={{ maxWidth: 240 }}>
|
||||||
{tab.title || 'Farm Control'}
|
{tab.title || 'Farm Control'}
|
||||||
</Text>
|
</Text>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import { getModelByName } from '../../../database/ObjectModels'
|
|||||||
import { getObjectIdFromSearch } from '../../../utils/modelActions'
|
import { getObjectIdFromSearch } from '../../../utils/modelActions'
|
||||||
import { useActions } from '../context/ActionsContext'
|
import { useActions } from '../context/ActionsContext'
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { useNavigationTabPage, useIsNavigationTabActive } from '../context/NavigationTabsContext'
|
import { useIsNavigationTabActive } from '../context/NavigationTabsContext'
|
||||||
|
import { useObjectNavigationTabPage } from '../hooks/useObjectNavigationTabPage'
|
||||||
|
|
||||||
const ModelPage = ({ modelName, pageName }) => {
|
const ModelPage = ({ modelName, pageName }) => {
|
||||||
const model = getModelByName(modelName)
|
const model = getModelByName(modelName)
|
||||||
@ -16,9 +17,8 @@ const ModelPage = ({ modelName, pageName }) => {
|
|||||||
const { setCurrentObject, setCurrentObjectType } = useActions()
|
const { setCurrentObject, setCurrentObjectType } = useActions()
|
||||||
const { userProfile } = useContext(AuthContext)
|
const { userProfile } = useContext(AuthContext)
|
||||||
const objectId = getObjectIdFromSearch(modelName, location.search)
|
const objectId = getObjectIdFromSearch(modelName, location.search)
|
||||||
const pageTitle = `${pageName.charAt(0).toUpperCase()}${pageName.slice(1)} - ${model?.label || modelName}`
|
|
||||||
const isTabActive = useIsNavigationTabActive()
|
const isTabActive = useIsNavigationTabActive()
|
||||||
useNavigationTabPage({ title: pageTitle, modelName })
|
useObjectNavigationTabPage({ modelName, pageName, objectId })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isTabActive) return undefined
|
if (!isTabActive) return undefined
|
||||||
|
|||||||
@ -131,7 +131,9 @@ export const ObjectListViewProvider = ({ children, objectType, tableRef }) => {
|
|||||||
const { getViewFromUrl, persistView, setObjectListView } = useTableState()
|
const { getViewFromUrl, persistView, setObjectListView } = useTableState()
|
||||||
const listModel = getModelByName(objectType)
|
const listModel = getModelByName(objectType)
|
||||||
useNavigationTabPage({
|
useNavigationTabPage({
|
||||||
title: listModel?.label ? `List - ${listModel.label}` : 'List',
|
title: listModel?.labelPlural
|
||||||
|
? `List - ${listModel.labelPlural}`
|
||||||
|
: 'List',
|
||||||
modelName: objectType
|
modelName: objectType
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
import { useContext, useEffect, useRef, useState } from 'react'
|
||||||
|
import { getModelByName } from '../../../database/ObjectModels'
|
||||||
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
import { useNavigationTabPage } from '../context/NavigationTabsContext'
|
||||||
|
|
||||||
|
const formatPageLabel = (pageName) =>
|
||||||
|
pageName
|
||||||
|
? `${pageName.charAt(0).toUpperCase()}${pageName.slice(1)}`
|
||||||
|
: 'Page'
|
||||||
|
|
||||||
|
const getObjectDisplayName = (objectData, model) => {
|
||||||
|
if (objectData?.name) return objectData.name
|
||||||
|
if (objectData?._reference && model?.prefix) {
|
||||||
|
return `${model.prefix}:${objectData._reference}`
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatObjectPageTabTitle = ({
|
||||||
|
pageName,
|
||||||
|
model,
|
||||||
|
objectName
|
||||||
|
} = {}) => {
|
||||||
|
const pageLabel = formatPageLabel(pageName)
|
||||||
|
const collectionLabel = model?.labelPlural
|
||||||
|
if (objectName && collectionLabel) {
|
||||||
|
return `${pageLabel} (${objectName}) - ${collectionLabel}`
|
||||||
|
}
|
||||||
|
if (objectName) return `${pageLabel} (${objectName})`
|
||||||
|
if (collectionLabel) return `${pageLabel} - ${collectionLabel}`
|
||||||
|
return pageLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useObjectNavigationTabPage = ({
|
||||||
|
modelName,
|
||||||
|
pageName,
|
||||||
|
objectId
|
||||||
|
} = {}) => {
|
||||||
|
const model = getModelByName(modelName)
|
||||||
|
const { fetchSpotlightData, subscribeToObjectUpdates, connected } =
|
||||||
|
useContext(ApiServerContext)
|
||||||
|
const { token } = useContext(AuthContext)
|
||||||
|
const [objectName, setObjectName] = useState(null)
|
||||||
|
const fetchSpotlightDataRef = useRef(fetchSpotlightData)
|
||||||
|
fetchSpotlightDataRef.current = fetchSpotlightData
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!objectId || !model?.prefix || token == null) {
|
||||||
|
setObjectName(null)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelled = false
|
||||||
|
const query = `${model.prefix}:${objectId}`
|
||||||
|
|
||||||
|
void fetchSpotlightDataRef.current(query).then((result) => {
|
||||||
|
if (cancelled) return
|
||||||
|
if (result && typeof result === 'object' && !Array.isArray(result)) {
|
||||||
|
setObjectName(getObjectDisplayName(result, model))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
}, [model, objectId, token])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!objectId || !modelName || !connected) return undefined
|
||||||
|
return subscribeToObjectUpdates(objectId, modelName, (value) => {
|
||||||
|
setObjectName((current) => getObjectDisplayName(value, model) || current)
|
||||||
|
})
|
||||||
|
}, [connected, model, modelName, objectId, subscribeToObjectUpdates])
|
||||||
|
|
||||||
|
useNavigationTabPage({
|
||||||
|
title: formatObjectPageTabTitle({ pageName, model, objectName }),
|
||||||
|
modelName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useObjectNavigationTabPage
|
||||||
Loading…
x
Reference in New Issue
Block a user