Skip to content

Commit 6510a01

Browse files
committed
Add follow-url click behaviour
1 parent 42aa050 commit 6510a01

File tree

2 files changed

+106
-101
lines changed

2 files changed

+106
-101
lines changed

src/components/result/GenericResultViewTag.tsx

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export interface GenericResultViewTagProps {
3131
* @param value
3232
*/
3333
singleValueMapper?: (value: string) => ReactNode
34-
onClick?: (e: MouseEvent<HTMLDivElement>, tagValue: ReactNode) => void
35-
clickBehavior?: "copy-text"
34+
onClick?: (e: MouseEvent<HTMLDivElement>, tagValue: ReactNode, fieldValue: string | string[]) => void
35+
clickBehavior?: "copy-text" | "follow-url"
3636
}
3737

3838
export function GenericResultViewTag({
@@ -45,13 +45,16 @@ export function GenericResultViewTag({
4545
clickBehavior = "copy-text",
4646
onClick
4747
}: GenericResultViewTagProps) {
48+
const fieldValue = useMemo(() => {
49+
return autoUnwrap(result[field]) as string | string[]
50+
}, [field, result])
51+
4852
const value = useMemo(() => {
49-
const value: string | string[] = autoUnwrap(result[field])
50-
if (!value) return undefined
51-
if (valueMapper) return valueMapper(value)
52-
if (singleValueMapper) return Array.isArray(value) ? value.map(singleValueMapper) : singleValueMapper(value)
53-
else return value
54-
}, [field, result, singleValueMapper, valueMapper])
53+
if (!fieldValue) return undefined
54+
if (valueMapper) return valueMapper(fieldValue)
55+
if (singleValueMapper) return Array.isArray(fieldValue) ? fieldValue.map(singleValueMapper) : singleValueMapper(fieldValue)
56+
else return fieldValue
57+
}, [fieldValue, singleValueMapper, valueMapper])
5558

5659
const [, copy] = useCopyToClipboard()
5760

@@ -65,19 +68,21 @@ export function GenericResultViewTag({
6568
)
6669

6770
const handleClick = useCallback(
68-
(value: ReactNode, e: MouseEvent<HTMLDivElement>) => {
69-
if (onClick) onClick(e, value)
71+
(fieldValue: string | string[], value: ReactNode, e: MouseEvent<HTMLDivElement>) => {
72+
if (onClick) onClick(e, value, fieldValue)
7073
if (clickBehavior === "copy-text") {
7174
copyTagValue(e)
75+
} else if (clickBehavior === "follow-url" && !Array.isArray(fieldValue)) {
76+
window.open(fieldValue, "_blank")
7277
}
7378
},
7479
[clickBehavior, copyTagValue, onClick]
7580
)
7681

7782
const base = useCallback(
78-
(value: ReactNode) => {
83+
(fieldValue: string | string[], value: ReactNode) => {
7984
return (
80-
<Badge variant="secondary" className="rfs-truncate" onClick={(e) => handleClick(value, e)}>
85+
<Badge variant="secondary" className="rfs-truncate" onClick={(e) => handleClick(fieldValue, value, e)}>
8186
<span className="rfs-flex rfs-truncate">
8287
{icon} {value}
8388
</span>
@@ -87,21 +92,21 @@ export function GenericResultViewTag({
8792
[handleClick, icon]
8893
)
8994

90-
if (!label) return base(value)
95+
if (!label) return Array.isArray(value) ? value.map((v) => base(fieldValue[value.indexOf(v)], v)) : base(fieldValue, value)
9196
if (!value) return null
9297

9398
if (Array.isArray(value)) {
9499
return value.map((entry, i) => (
95100
<Tooltip delayDuration={500} key={i}>
96-
<TooltipTrigger>{base(entry)}</TooltipTrigger>
101+
<TooltipTrigger>{base(fieldValue[value.indexOf(entry)], entry)}</TooltipTrigger>
97102
<TooltipContent>{label}</TooltipContent>
98103
</Tooltip>
99104
))
100105
}
101106

102107
return (
103108
<Tooltip delayDuration={500}>
104-
<TooltipTrigger>{base(value)}</TooltipTrigger>
109+
<TooltipTrigger>{base(fieldValue, value)}</TooltipTrigger>
105110
<TooltipContent>{label}</TooltipContent>
106111
</Tooltip>
107112
)

src/stories/FairDOElasticSearch.stories.tsx

Lines changed: 86 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type { Meta, StoryObj } from "@storybook/react"
44
import { FairDOElasticSearch } from "@/components/FairDOElasticSearch"
55
import { GenericResultView } from "@/components/result/GenericResultView"
66
import { AtomIcon, AudioLines, CircleDot, GlobeIcon, GraduationCap, Microscope, ScaleIcon, UserIcon } from "lucide-react"
7-
import { tryURLPrettyPrint } from "@/lib/utils"
87
import { PidDisplay } from "@/components/result/PidDisplay"
98
import { OrcidDisplay } from "@/components/result/OrcidDisplay"
109

@@ -111,44 +110,44 @@ const demoConfig: FairDOConfig = {
111110
]
112111
}
113112

114-
const demoConfigWithCompound: FairDOConfig = {
115-
debug: false,
116-
alwaysSearchOnInitialLoad: true,
117-
// host: "https://matwerk.datamanager.kit.edu/search-proxy/api/v1",
118-
host: "https://ddaa9283-f114-4496-b6ed-af12ee34b107.ka.bw-cloud-instance.org:9200",
119-
apiKey: "UGNoTW1KUUJ3WmluUHBTcEVpalo6cGloOUVKZ0tTdnlMYVlpTzV4SXBrUQ==",
120-
indices: [
121-
{
122-
name: "fdo-prod",
123-
facets: [
124-
{
125-
key: "Compound.Molar_mass",
126-
label: "Compound",
127-
type: "min-max-slider"
128-
}
129-
],
130-
resultFields: [], // Leave empty to get all fields
131-
searchFields: ["name", "pid", "hasMetadata", "isMetadataFor", "NMR_Method"]
132-
}
133-
],
134-
initialState: {
135-
sortList: [
136-
{
137-
field: "_score",
138-
direction: "desc"
139-
},
140-
{
141-
field: "name.keyword",
142-
direction: "asc"
143-
},
144-
{
145-
field: "locationPreview/Sample.keyword",
146-
direction: "asc"
147-
}
148-
]
149-
},
150-
disjunctiveFacets: ["NMR_Method.keyword"]
151-
}
113+
// const demoConfigWithCompound: FairDOConfig = {
114+
// debug: false,
115+
// alwaysSearchOnInitialLoad: true,
116+
// // host: "https://matwerk.datamanager.kit.edu/search-proxy/api/v1",
117+
// host: "https://ddaa9283-f114-4496-b6ed-af12ee34b107.ka.bw-cloud-instance.org:9200",
118+
// apiKey: "UGNoTW1KUUJ3WmluUHBTcEVpalo6cGloOUVKZ0tTdnlMYVlpTzV4SXBrUQ==",
119+
// indices: [
120+
// {
121+
// name: "fdo-prod",
122+
// facets: [
123+
// {
124+
// key: "Compound.Molar_mass",
125+
// label: "Compound",
126+
// type: "min-max-slider"
127+
// }
128+
// ],
129+
// resultFields: [], // Leave empty to get all fields
130+
// searchFields: ["name", "pid", "hasMetadata", "isMetadataFor", "NMR_Method"]
131+
// }
132+
// ],
133+
// initialState: {
134+
// sortList: [
135+
// {
136+
// field: "_score",
137+
// direction: "desc"
138+
// },
139+
// {
140+
// field: "name.keyword",
141+
// direction: "asc"
142+
// },
143+
// {
144+
// field: "locationPreview/Sample.keyword",
145+
// direction: "asc"
146+
// }
147+
// ]
148+
// },
149+
// disjunctiveFacets: ["NMR_Method.keyword"]
150+
// }
152151

153152
export const NoResultRenderer: Story = {
154153
args: {
@@ -169,7 +168,8 @@ export const GenericResultRenderer: Story = {
169168
icon: <UserIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
170169
label: "Contact",
171170
field: "contact",
172-
singleValueMapper: (v) => <OrcidDisplay orcid={v} />
171+
singleValueMapper: (v) => <OrcidDisplay orcid={v} />,
172+
clickBehavior: "follow-url"
173173
},
174174
{
175175
icon: <GraduationCap className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
@@ -228,49 +228,49 @@ export const GenericResultRenderer: Story = {
228228
}
229229
}
230230

231-
export const CompoundSlider: Story = {
232-
args: {
233-
config: demoConfigWithCompound,
234-
resultView: (props) => (
235-
<GenericResultView
236-
result={props.result}
237-
invertImageInDarkMode
238-
tags={[
239-
{
240-
icon: <GraduationCap className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
241-
label: "Resource Type",
242-
field: "resourceType"
243-
},
244-
{
245-
icon: <GlobeIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
246-
field: "hadPrimarySource",
247-
valueMapper: (v) => tryURLPrettyPrint(v + ""),
248-
label: "Source"
249-
},
250-
{
251-
icon: <ScaleIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
252-
field: "licenseURL",
253-
valueMapper: (v) => tryURLPrettyPrint(v + ""),
254-
label: "License URL"
255-
},
256-
{
257-
icon: <AtomIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
258-
field: "Compound.Molar_mass",
259-
label: "Molar Mass",
260-
valueMapper: (v) => v + " g/mol"
261-
}
262-
]}
263-
titleField="name"
264-
creationDateField="dateCreatedRfc3339"
265-
additionalIdentifierField="identifier"
266-
digitalObjectLocationField="digitalObjectLocation"
267-
imageField="locationPreview/Sample"
268-
parentItemPidField="hasMetadata"
269-
relatedItemPidsField="isMetadataFor"
270-
pidField="pid"
271-
relatedItemsPrefetch={{ searchFields: { pid: {} } }}
272-
showOpenInFairDoScope
273-
/>
274-
)
275-
}
276-
}
231+
// export const CompoundSlider: Story = {
232+
// args: {
233+
// config: demoConfigWithCompound,
234+
// resultView: (props) => (
235+
// <GenericResultView
236+
// result={props.result}
237+
// invertImageInDarkMode
238+
// tags={[
239+
// {
240+
// icon: <GraduationCap className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
241+
// label: "Resource Type",
242+
// field: "resourceType"
243+
// },
244+
// {
245+
// icon: <GlobeIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
246+
// field: "hadPrimarySource",
247+
// valueMapper: (v) => tryURLPrettyPrint(v + ""),
248+
// label: "Source"
249+
// },
250+
// {
251+
// icon: <ScaleIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
252+
// field: "licenseURL",
253+
// valueMapper: (v) => tryURLPrettyPrint(v + ""),
254+
// label: "License URL"
255+
// },
256+
// {
257+
// icon: <AtomIcon className="rfs-shrink-0 rfs-size-4 rfs-mr-2" />,
258+
// field: "Compound.Molar_mass",
259+
// label: "Molar Mass",
260+
// valueMapper: (v) => v + " g/mol"
261+
// }
262+
// ]}
263+
// titleField="name"
264+
// creationDateField="dateCreatedRfc3339"
265+
// additionalIdentifierField="identifier"
266+
// digitalObjectLocationField="digitalObjectLocation"
267+
// imageField="locationPreview/Sample"
268+
// parentItemPidField="hasMetadata"
269+
// relatedItemPidsField="isMetadataFor"
270+
// pidField="pid"
271+
// relatedItemsPrefetch={{ searchFields: { pid: {} } }}
272+
// showOpenInFairDoScope
273+
// />
274+
// )
275+
// }
276+
// }

0 commit comments

Comments
 (0)