diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css
index 01677eec..3df85f1d 100644
--- a/assets/stylesheets/App.css
+++ b/assets/stylesheets/App.css
@@ -484,6 +484,11 @@ code {
padding: 0 !important;
}
+.spotlight-tooltip.ant-card,
+.spotlight-tooltip .ant-card {
+ background: transparent !important;
+}
+
.ant-popover:has(.spotlight-tooltip) {
z-index: 1051;
}
diff --git a/src/components/Dashboard/common/SpotlightTooltip.jsx b/src/components/Dashboard/common/SpotlightTooltip.jsx
index 340f5e87..1b0f52dd 100644
--- a/src/components/Dashboard/common/SpotlightTooltip.jsx
+++ b/src/components/Dashboard/common/SpotlightTooltip.jsx
@@ -1,34 +1,102 @@
// SpotlightTooltip.js
import PropTypes from 'prop-types'
-import { Descriptions, Card, Flex, Typography, Skeleton, Spin } from 'antd'
-import { LoadingOutlined } from '@ant-design/icons'
-import { useEffect, useState, useContext, useCallback } from 'react'
+import { Button, Card, Flex, Typography } from 'antd'
+import {
+ createElement,
+ useEffect,
+ useState,
+ useContext,
+ useCallback,
+ useMemo
+} from 'react'
import { AuthContext } from '../context/AuthContext'
-import ObjectProperty from './ObjectProperty'
+import { useActions } from '../context/ActionsContext'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
+import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
import { ApiServerContext } from '../context/ApiServerContext'
import merge from 'lodash/merge'
-import {
- getModelByName,
- getModelProperty
-} from '../../../database/ObjectModels'
+import { getModelByName } from '../../../database/ObjectModels'
+import { hasActionPermission } from '../../../database/permissions'
+import ObjectCard from './ObjectCard'
+import Tooltip from './Tooltip'
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 [spotlightData, setSpotlightData] = useState(null)
const [loading, setLoading] = useState(true)
const [initialized, setInitialized] = useState(false)
- const { token } = useContext(AuthContext)
+ const { token, userProfile } = useContext(AuthContext)
+ const { callAction } = useActions()
const { fetchSpotlightData, subscribeToObjectUpdates, connected } =
useContext(ApiServerContext)
- // Get the model for this type
const model = getModelByName(type)
const modelProperties = model.properties || []
+ const rowActions = useMemo(
+ () => model.actions?.filter((action) => action.row == true) || [],
+ [model]
+ )
+
+ const renderActions = useCallback(
+ (objectData, actionsDisabled = false) => {
+ return (
+
+ {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 (
+
+
+ )
+ }
+ disabled={disabled || objectData?.isSkeleton}
+ type={'text'}
+ size={'small'}
+ danger={action?.danger || false}
+ onClick={() => {
+ if (denied) return
+ callAction(
+ action,
+ { ...objectData, _user: userProfile },
+ type
+ )
+ }}
+ />
+
+ )
+ })}
+
+ )
+ },
+ [callAction, model, rowActions, type, userProfile]
+ )
- // Update event handler
const updateObjectEventHandler = useCallback((value) => {
setSpotlightData((prev) => merge({}, prev, value))
}, [])
@@ -47,7 +115,6 @@ const SpotlightTooltip = ({ query, type }) => {
}
}, [token, fetchSpotlight, initialized])
- // Subscribe to object updates when component mounts
useEffect(() => {
if (spotlightData?._id && type && connected && token) {
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
@@ -69,6 +136,28 @@ const SpotlightTooltip = ({ query, type }) => {
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) {
return (
@@ -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 (
-
-
} spinning={loading}>
-
- {loading ? (
- <>
-
- }
- >
-
-
-
- }
- >
-
-
-
- }
- >
-
-
- >
- ) : (
- modelProperties
- .filter((prop) => {
- const value = getNestedValue(spotlightData, prop.name)
- return value !== undefined && value !== null && value !== ''
- })
- .map((prop) => {
- const value = getNestedValue(spotlightData, prop.name)
- return (
-
-
-
- )
- })
- )}
-
-
+
+
)
}