Implement search functionality for models by label in SpotlightContext and update list data handling to include model actions. Enhance model retrieval logic for improved user interaction in the dashboard.
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

This commit is contained in:
Tom Butcher 2026-06-25 01:00:33 +01:00
parent 2df25364a0
commit a896cdf223
2 changed files with 46 additions and 8 deletions

View File

@ -30,9 +30,11 @@ import IdDisplay from '../common/IdDisplay'
import config from '../../../config' import config from '../../../config'
import { import {
getModelByName, getModelByName,
getModelByPrefix getModelByPrefix,
searchModelsByLabel
} from '../../../database/ObjectModels' } from '../../../database/ObjectModels'
import InfoCircleIcon from '../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import MenuIcon from '../../Icons/MenuIcon'
import { ApiServerContext } from './ApiServerContext' import { ApiServerContext } from './ApiServerContext'
import { AuthContext } from './AuthContext' import { AuthContext } from './AuthContext'
import { ElectronContext } from './ElectronContext' import { ElectronContext } from './ElectronContext'
@ -128,6 +130,22 @@ const SpotlightContent = ({
} }
setLoading(false) setLoading(false)
const models = searchModelsByLabel(searchQuery.trim()).map((model) => ({
type: model.name,
name: model.labelPlural,
icon: model.icon,
actions: [
{
default: true,
row: true,
icon: MenuIcon,
url: () => {
return model.url
}
}
]
}))
// If the query contains a prefix mode character, and the response is an object, wrap it in an array // If the query contains a prefix mode character, and the response is an object, wrap it in an array
if ( if (
/[:?^]/.test(searchQuery) && /[:?^]/.test(searchQuery) &&
@ -135,9 +153,9 @@ const SpotlightContent = ({
!Array.isArray(data) && !Array.isArray(data) &&
typeof data === 'object' typeof data === 'object'
) { ) {
setListData([data]) setListData([...models, data])
} else { } else {
setListData(data) setListData([...models, ...data])
} }
// Check if there's a pending query after this fetch completes // Check if there's a pending query after this fetch completes
@ -290,7 +308,11 @@ const SpotlightContent = ({
const item = listData[0] const item = listData[0]
let type = item.type || item.objectType || inputPrefix?.type let type = item.type || item.objectType || inputPrefix?.type
const model = getModelByName(type) const model = getModelByName(type)
const defaultAction = model ? getDefaultRowAction(model) : null const defaultAction = item?.type
? getDefaultRowAction(item)
: model
? getDefaultRowAction(model)
: null
if (defaultAction) { if (defaultAction) {
triggerRowAction(defaultAction, item) triggerRowAction(defaultAction, item)
} }
@ -304,7 +326,11 @@ const SpotlightContent = ({
const item = listData[index] const item = listData[index]
let type = item.type || item.objectType || inputPrefix?.type let type = item.type || item.objectType || inputPrefix?.type
const model = getModelByName(type) const model = getModelByName(type)
const defaultAction = model ? getDefaultRowAction(model) : null const defaultAction = item?.type
? getDefaultRowAction(item)
: model
? getDefaultRowAction(model)
: null
if (defaultAction) { if (defaultAction) {
triggerRowAction(defaultAction, item) triggerRowAction(defaultAction, item)
} }
@ -447,10 +473,12 @@ const SpotlightContent = ({
<List <List
dataSource={listData} dataSource={listData}
renderItem={(item, index) => { renderItem={(item, index) => {
let type = item.objectType || inputPrefix?.type let type = item.objectType || inputPrefix?.type || item?.type
const model = getModelByName(type) const model = getModelByName(type)
const Icon = model?.icon const Icon = model?.icon
const rowActions = getRowActions(model) const rowActions = item?.type
? item.actions
: getRowActions(model)
let shortcutText = '' let shortcutText = ''
if (index === 0) { if (index === 0) {
shortcutText = 'ENTER' shortcutText = 'ENTER'
@ -492,7 +520,9 @@ const SpotlightContent = ({
showId={false} showId={false}
/> />
) : null} ) : null}
<IdDisplay id={item._id} type={type} longId={false} /> {item?._id ? (
<IdDisplay id={item._id} type={type} longId={false} />
) : null}
</Flex> </Flex>
<Flex gap={'small'}> <Flex gap={'small'}>
{rowActions {rowActions

View File

@ -213,6 +213,14 @@ export function getModelByPrefix(prefix) {
) )
} }
export function searchModelsByLabel(label) {
return objectModels.filter(
(meta) =>
meta.label.toLowerCase().includes(label.toLowerCase()) ||
meta.labelPlural.toLowerCase().includes(label.toLowerCase())
)
}
// Utility function to get nested object values // Utility function to get nested object values
export const getPropertyValue = (obj, path) => { export const getPropertyValue = (obj, path) => {
if (!obj || !path) return undefined if (!obj || !path) return undefined