diff --git a/src/lib/vis/components/VisualizationTabBar.tsx b/src/lib/vis/components/VisualizationTabBar.tsx index 5110f6b0862dacaa3617266d70c0a2ee92b5d5bd..e66341543d3d43332fef3a2f7dd9650a9d542084 100644 --- a/src/lib/vis/components/VisualizationTabBar.tsx +++ b/src/lib/vis/components/VisualizationTabBar.tsx @@ -107,10 +107,10 @@ export default function VisualizationTabBar(props: { fullSize: () => void; expor label={displayName} className="flex items-center gap-2" onClick={async () => { + setOpen(false); dispatch(resultSetFocus({ focusType: 'visualization' })); const component = await Visualizations[id](); dispatch(addVisualization({ ...component.default.settings, name: displayName, id })); - setOpen(false); }} > {icons.sm && <icons.sm className="h-4 w-4" />} diff --git a/src/lib/vis/views/Recommender.tsx b/src/lib/vis/views/Recommender.tsx index 6d153798ebe8bfd445904d2ca30575cbab734544..209a3adda961dc6a695bf070f04c77513d317ea0 100644 --- a/src/lib/vis/views/Recommender.tsx +++ b/src/lib/vis/views/Recommender.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import Info from '../../components/info'; import { addVisualization } from '../../data-access/store/visualizationSlice'; import { useActiveSaveStateAuthorization, useAppDispatch } from '../../data-access'; @@ -11,10 +11,11 @@ export function Recommender() { const saveStateAuthorization = useActiveSaveStateAuthorization(); const [visualizationDescriptions] = useState(Object.values(VisualizationsConfig)); + const ref = useRef<HTMLDivElement>(); return ( <div className="p-4"> <span className="text-md">Select a visualization</span> - <div className="grid gap-3 my-2" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))' }}> + <div className="grid gap-3 my-2" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))' }} ref={ref}> {visualizationDescriptions.map(({ id, displayName, description, icons }) => { const IconComponent = icons.lg; @@ -24,6 +25,9 @@ export function Recommender() { className={`group flex flex-row gap-1.5 items-start rounded-md relative p-2 border h-18 ${saveStateAuthorization.visualization.W ? 'cursor-pointer hover:bg-secondary-100' : 'cursor-not-allowed opacity-50'}`} onClick={async e => { e.preventDefault(); + // Ensure no new pointer events are passed, preventing doubleclick to open multiple visualizations. + ref.current.classList.add('pointer-events-none'); + if (!saveStateAuthorization.visualization.W) { console.debug('User blocked from editing query due to being a viewer'); return; @@ -31,6 +35,8 @@ export function Recommender() { dispatch(resultSetFocus({ focusType: 'visualization' })); const component = await Visualizations[id](); dispatch(addVisualization({ ...component.default.settings, name: displayName, id })); + + ref.current.classList.remove('pointer-events-none'); }} > <div className="text-secondary-500 group-hover:text-secondary-700">