Enhance SpotlightTooltip Component and Update Styles
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Refactored SpotlightTooltip component to improve action handling and data rendering. - Introduced new utility functions for value checking and nested property access. - Updated rendering logic to utilize ObjectCard for better display of spotlight data. - Added CSS styles for spotlight tooltip to ensure a transparent background.
This commit is contained in:
parent
3544ac0d89
commit
f0b0ad41a6
@ -484,6 +484,11 @@ code {
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spotlight-tooltip.ant-card,
|
||||||
|
.spotlight-tooltip .ant-card {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
.ant-popover:has(.spotlight-tooltip) {
|
.ant-popover:has(.spotlight-tooltip) {
|
||||||
z-index: 1051;
|
z-index: 1051;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,102 @@
|
|||||||
// SpotlightTooltip.js
|
// SpotlightTooltip.js
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Descriptions, Card, Flex, Typography, Skeleton, Spin } from 'antd'
|
import { Button, Card, Flex, Typography } from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import {
|
||||||
import { useEffect, useState, useContext, useCallback } from 'react'
|
createElement,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
useMemo
|
||||||
|
} from 'react'
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import ObjectProperty from './ObjectProperty'
|
import { useActions } from '../context/ActionsContext'
|
||||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
|
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||||
import { ApiServerContext } from '../context/ApiServerContext'
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
import merge from 'lodash/merge'
|
import merge from 'lodash/merge'
|
||||||
import {
|
import { getModelByName } from '../../../database/ObjectModels'
|
||||||
getModelByName,
|
import { hasActionPermission } from '../../../database/permissions'
|
||||||
getModelProperty
|
import ObjectCard from './ObjectCard'
|
||||||
} from '../../../database/ObjectModels'
|
import Tooltip from './Tooltip'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
|
const hasValue = (value) => value !== undefined && value !== null && value !== ''
|
||||||
|
|
||||||
|
const getNestedValue = (obj, path) => {
|
||||||
|
return path.split('.').reduce((current, key) => current?.[key], obj)
|
||||||
|
}
|
||||||
|
|
||||||
const SpotlightTooltip = ({ query, type }) => {
|
const SpotlightTooltip = ({ query, type }) => {
|
||||||
const [spotlightData, setSpotlightData] = useState(null)
|
const [spotlightData, setSpotlightData] = useState(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
|
|
||||||
const { token } = useContext(AuthContext)
|
const { token, userProfile } = useContext(AuthContext)
|
||||||
|
const { callAction } = useActions()
|
||||||
const { fetchSpotlightData, subscribeToObjectUpdates, connected } =
|
const { fetchSpotlightData, subscribeToObjectUpdates, connected } =
|
||||||
useContext(ApiServerContext)
|
useContext(ApiServerContext)
|
||||||
|
|
||||||
// Get the model for this type
|
|
||||||
const model = getModelByName(type)
|
const model = getModelByName(type)
|
||||||
const modelProperties = model.properties || []
|
const modelProperties = model.properties || []
|
||||||
|
const rowActions = useMemo(
|
||||||
|
() => model.actions?.filter((action) => action.row == true) || [],
|
||||||
|
[model]
|
||||||
|
)
|
||||||
|
|
||||||
|
const renderActions = useCallback(
|
||||||
|
(objectData, actionsDisabled = false) => {
|
||||||
|
return (
|
||||||
|
<Flex gap='small' align='center' justify='center'>
|
||||||
|
{rowActions.map((action, index) => {
|
||||||
|
const denied = !hasActionPermission(userProfile, model, action.name)
|
||||||
|
var disabled = denied
|
||||||
|
if (action.disabled) {
|
||||||
|
if (typeof action.disabled === 'function') {
|
||||||
|
disabled =
|
||||||
|
denied ||
|
||||||
|
action.disabled({
|
||||||
|
...objectData,
|
||||||
|
_user: userProfile
|
||||||
|
}) ||
|
||||||
|
actionsDisabled
|
||||||
|
} else {
|
||||||
|
disabled = denied || action.disabled || actionsDisabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip key={index} title={action.label}>
|
||||||
|
<Button
|
||||||
|
icon={
|
||||||
|
action.icon ? (
|
||||||
|
createElement(action.icon)
|
||||||
|
) : (
|
||||||
|
<QuestionCircleIcon />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
disabled={disabled || objectData?.isSkeleton}
|
||||||
|
type={'text'}
|
||||||
|
size={'small'}
|
||||||
|
danger={action?.danger || false}
|
||||||
|
onClick={() => {
|
||||||
|
if (denied) return
|
||||||
|
callAction(
|
||||||
|
action,
|
||||||
|
{ ...objectData, _user: userProfile },
|
||||||
|
type
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[callAction, model, rowActions, type, userProfile]
|
||||||
|
)
|
||||||
|
|
||||||
// Update event handler
|
|
||||||
const updateObjectEventHandler = useCallback((value) => {
|
const updateObjectEventHandler = useCallback((value) => {
|
||||||
setSpotlightData((prev) => merge({}, prev, value))
|
setSpotlightData((prev) => merge({}, prev, value))
|
||||||
}, [])
|
}, [])
|
||||||
@ -47,7 +115,6 @@ const SpotlightTooltip = ({ query, type }) => {
|
|||||||
}
|
}
|
||||||
}, [token, fetchSpotlight, initialized])
|
}, [token, fetchSpotlight, initialized])
|
||||||
|
|
||||||
// Subscribe to object updates when component mounts
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (spotlightData?._id && type && connected && token) {
|
if (spotlightData?._id && type && connected && token) {
|
||||||
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
|
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
|
||||||
@ -69,6 +136,28 @@ const SpotlightTooltip = ({ query, type }) => {
|
|||||||
updateObjectEventHandler
|
updateObjectEventHandler
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const visibleColumns = useMemo(() => {
|
||||||
|
const columnNames = model.columns || []
|
||||||
|
const columns = { name: true }
|
||||||
|
|
||||||
|
if (!spotlightData) {
|
||||||
|
columnNames.slice(0, 4).forEach((colName) => {
|
||||||
|
columns[colName] = true
|
||||||
|
})
|
||||||
|
columnNames.forEach((colName) => {
|
||||||
|
if (columns[colName] == null) columns[colName] = false
|
||||||
|
})
|
||||||
|
return columns
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const colName of columnNames) {
|
||||||
|
if (colName === 'name') continue
|
||||||
|
columns[colName] = hasValue(getNestedValue(spotlightData, colName))
|
||||||
|
}
|
||||||
|
|
||||||
|
return columns
|
||||||
|
}, [model.columns, spotlightData])
|
||||||
|
|
||||||
if (!spotlightData && !loading) {
|
if (!spotlightData && !loading) {
|
||||||
return (
|
return (
|
||||||
<Card className='spotlight-tooltip'>
|
<Card className='spotlight-tooltip'>
|
||||||
@ -87,68 +176,24 @@ const SpotlightTooltip = ({ query, type }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to get nested property value
|
|
||||||
const getNestedValue = (obj, path) => {
|
|
||||||
return path.split('.').reduce((current, key) => current?.[key], obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='spotlight-tooltip'>
|
<div className='spotlight-tooltip' style={{ width: 360 }}>
|
||||||
<Spin indicator={<LoadingOutlined />} spinning={loading}>
|
<ObjectCard
|
||||||
<Descriptions bordered column={1} size='small'>
|
isSkeleton={!spotlightData && loading}
|
||||||
{loading ? (
|
model={model}
|
||||||
<>
|
modelProperties={modelProperties}
|
||||||
<Descriptions.Item
|
visibleColumns={visibleColumns}
|
||||||
label={
|
record={
|
||||||
<Skeleton.Input active size='small' style={{ width: 80 }} />
|
spotlightData || {
|
||||||
}
|
_id: query,
|
||||||
>
|
isSkeleton: true
|
||||||
<Skeleton.Input active size='small' style={{ width: 120 }} />
|
}
|
||||||
</Descriptions.Item>
|
}
|
||||||
<Descriptions.Item
|
isEditing={false}
|
||||||
label={
|
rowActions={rowActions}
|
||||||
<Skeleton.Input active size='small' style={{ width: 80 }} />
|
renderActions={renderActions}
|
||||||
}
|
cardStyle='borderless'
|
||||||
>
|
/>
|
||||||
<Skeleton.Input active size='small' style={{ width: 120 }} />
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item
|
|
||||||
label={
|
|
||||||
<Skeleton.Input active size='small' style={{ width: 80 }} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Skeleton.Input active size='small' style={{ width: 120 }} />
|
|
||||||
</Descriptions.Item>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
modelProperties
|
|
||||||
.filter((prop) => {
|
|
||||||
const value = getNestedValue(spotlightData, prop.name)
|
|
||||||
return value !== undefined && value !== null && value !== ''
|
|
||||||
})
|
|
||||||
.map((prop) => {
|
|
||||||
const value = getNestedValue(spotlightData, prop.name)
|
|
||||||
return (
|
|
||||||
<Descriptions.Item key={prop.name} label={prop.label}>
|
|
||||||
<ObjectProperty
|
|
||||||
{...getModelProperty(type, prop.name)}
|
|
||||||
value={value}
|
|
||||||
objectData={spotlightData}
|
|
||||||
objectType={prop.objectType || type}
|
|
||||||
isEditing={false}
|
|
||||||
longId={false}
|
|
||||||
showSpotlight={false}
|
|
||||||
showLabel={false}
|
|
||||||
showName={false}
|
|
||||||
showId={false}
|
|
||||||
showQuantity={false}
|
|
||||||
/>
|
|
||||||
</Descriptions.Item>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
</Descriptions>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user