11import { MouseEvent , ReactNode , useCallback , useEffect , useMemo , useState } from "react"
22import { Tooltip , TooltipContent , TooltipTrigger } from "@/components/ui/tooltip"
33import { Badge } from "@/components/ui/badge"
4- import { SearchResult } from "@elastic/search-ui"
4+ import { SearchResult , FieldValue } from "@elastic/search-ui"
55import { useCopyToClipboard } from "usehooks-ts"
66import { CheckIcon } from "lucide-react"
77import { autoUnwrap } from "@/lib/utils"
@@ -11,6 +11,10 @@ export interface GenericResultViewTagProps {
1111 * The elasticsearch field that this tag will display
1212 */
1313 field : string
14+ /**
15+ * When specified, does not read the field from elastic and instead just displays this value
16+ */
17+ valueOverride ?: string | number | boolean
1418 result : SearchResult
1519 /**
1620 * Icon for this tag, can be any react component. Ideally a [lucide icon](https://lucide.dev) with 16px by 16px site.
@@ -25,27 +29,20 @@ export interface GenericResultViewTagProps {
2529 * Can't the used together with `singleValueMapper`
2630 * @param value
2731 */
28- valueMapper ?: ( value : string | string [ ] ) => ReactNode
32+ valueMapper ?: ( value : FieldValue ) => ReactNode
2933 /**
3034 * Optional, here you can map each value of the elasticsearch field to a string or a React component. Can't be used
3135 * together with `valueMapper`
3236 * @param value
3337 */
34- singleValueMapper ?: ( value : string ) => ReactNode
35- onClick ?: ( e : MouseEvent < HTMLDivElement > , tagValue : ReactNode , fieldValue : string | string [ ] ) => void
38+ singleValueMapper ?: ( value : string | number | boolean ) => ReactNode
39+ onClick ?: ( e : MouseEvent < HTMLDivElement > , tagValue : ReactNode , fieldValue : FieldValue ) => void
3640 clickBehavior ?: "copy-text" | "follow-url" | string
3741}
3842
39- export function GenericResultViewTag ( {
40- field,
41- result,
42- icon,
43- label,
44- valueMapper,
45- singleValueMapper,
46- clickBehavior = "copy-text" ,
47- onClick
48- } : GenericResultViewTagProps ) {
43+ export function GenericResultViewTag ( props : GenericResultViewTagProps ) {
44+ const { field, valueOverride, result, icon, label, valueMapper, singleValueMapper, clickBehavior = "copy-text" , onClick } = props
45+
4946 const [ showCopiedNotice , setShowCopiedNotice ] = useState ( false )
5047
5148 useEffect ( ( ) => {
@@ -57,11 +54,12 @@ export function GenericResultViewTag({
5754 } , [ showCopiedNotice ] )
5855
5956 const fieldValue = useMemo ( ( ) => {
60- return autoUnwrap ( result [ field ] ) as string | string [ ]
61- } , [ field , result ] )
57+ if ( valueOverride !== undefined ) return valueOverride
58+ return autoUnwrap ( result [ field ] ) as FieldValue
59+ } , [ field , result , valueOverride ] )
6260
6361 const value = useMemo ( ( ) => {
64- if ( ! fieldValue ) return undefined
62+ if ( fieldValue === null || fieldValue === undefined ) return undefined
6563 if ( valueMapper ) return valueMapper ( fieldValue )
6664 if ( singleValueMapper ) return Array . isArray ( fieldValue ) ? fieldValue . map ( singleValueMapper ) : singleValueMapper ( fieldValue )
6765 else return fieldValue
@@ -79,13 +77,13 @@ export function GenericResultViewTag({
7977 )
8078
8179 const handleClick = useCallback (
82- ( fieldValue : string | string [ ] , value : ReactNode , e : MouseEvent < HTMLDivElement > ) => {
80+ ( fieldValue : FieldValue , value : ReactNode , e : MouseEvent < HTMLDivElement > ) => {
8381 if ( onClick ) onClick ( e , value , fieldValue )
8482 if ( clickBehavior === "copy-text" && ! showCopiedNotice ) {
8583 copyTagValue ( e )
8684 setShowCopiedNotice ( true )
8785 } else if ( clickBehavior === "follow-url" && ! Array . isArray ( fieldValue ) ) {
88- window . open ( fieldValue , "_blank" )
86+ window . open ( fieldValue . toString ( ) , "_blank" )
8987 }
9088 } ,
9189 [ clickBehavior , copyTagValue , onClick , showCopiedNotice ]
@@ -101,7 +99,7 @@ export function GenericResultViewTag({
10199 } , [ clickBehavior , onClick ] )
102100
103101 const base = useCallback (
104- ( fieldValue : string | string [ ] , value : ReactNode , key ?: string ) => {
102+ ( fieldValue : FieldValue , value : ReactNode , key ?: string ) => {
105103 return (
106104 < Badge key = { key } variant = "secondary" className = "rfs-truncate" onClick = { ( e ) => handleClick ( fieldValue , value , e ) } >
107105 < span className = "rfs-flex rfs-truncate" >
@@ -121,19 +119,12 @@ export function GenericResultViewTag({
121119 [ handleClick , icon , showCopiedNotice ]
122120 )
123121
124- if ( ! label ) return Array . isArray ( value ) ? value . map ( ( v , i ) => base ( fieldValue [ value . indexOf ( v ) ] , v , field + i ) ) : base ( fieldValue , value )
125- if ( ! value ) return null
122+ if ( value === undefined ) return null
126123
127- if ( Array . isArray ( value ) ) {
128- return value . map ( ( entry , i ) => (
129- < Tooltip delayDuration = { 500 } key = { field + i } >
130- < TooltipTrigger > { base ( fieldValue [ value . indexOf ( entry ) ] , entry ) } </ TooltipTrigger >
131- < TooltipContent >
132- < div > { label } </ div >
133- < div className = "rfs-text-xs rfs-text-muted-foreground" > { clickBehaviourText } </ div >
134- </ TooltipContent >
135- </ Tooltip >
136- ) )
124+ if ( Array . isArray ( value ) && Array . isArray ( fieldValue ) ) {
125+ return value . map ( ( entry , i ) => < GenericResultViewTag { ...props } key = { field + i } valueOverride = { fieldValue [ value . indexOf ( entry ) ] } /> )
126+ } else if ( ! label ) {
127+ return base ( fieldValue , value )
137128 }
138129
139130 return (
0 commit comments