Mirror of https://github.com/roostorg/osprey github.com/roostorg/osprey
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 137 lines 4.1 kB view raw
1import * as React from 'react'; 2import classNames from 'classnames'; 3import shallow from 'zustand/shallow'; 4 5import useQueryStore from '../../stores/QueryStore'; 6import OspreyButton, { ButtonColors, ButtonHeights, ButtonWeights } from '../../uikit/OspreyButton'; 7import Text, { TextColors, TextSizes, TextWeights } from '../../uikit/Text'; 8import { addFeaturesToQueryFilter } from '../../utils/QueryUtils'; 9import { openNewQueryWindow } from '../../utils/SearchParamUtils'; 10 11import styles from './Feature.module.css'; 12 13interface CommonFeatureProps { 14 featureName: string; 15 onClick?: () => void; 16 className?: string; 17 isEntity?: boolean; 18 textSelectable?: boolean; 19 isFeatureNameOnly?: boolean; 20} 21 22type SelectableFeatureProps = CommonFeatureProps & { 23 value: string | null; 24}; 25 26const SelectableFeature = ({ 27 featureName, 28 value, 29 onClick, 30 className, 31 isEntity = false, 32 textSelectable = true, 33 isFeatureNameOnly = false, 34}: SelectableFeatureProps): React.ReactElement => { 35 const [queuedQueryFilters, updateQueuedQueryFilters] = useQueryStore( 36 (state) => [state.queuedQueryFilters, state.updateQueuedQueryFilters], 37 shallow 38 ); 39 const [isSelected, setIsSelected] = React.useState(false); 40 41 React.useEffect(() => { 42 if (isSelected && queuedQueryFilters.length === 0) { 43 setIsSelected(false); 44 } 45 }, [isSelected, queuedQueryFilters.length]); 46 47 const handleFeatureClick = (e: React.MouseEvent<HTMLButtonElement>) => { 48 const feature = { value, featureName }; 49 50 if (e.shiftKey) { 51 const filteredFeatures = queuedQueryFilters.filter((queuedFilter) => { 52 return queuedFilter.value !== value || queuedFilter.featureName !== featureName; 53 }); 54 const featureNotYetQueued = filteredFeatures.length === queuedQueryFilters.length; 55 56 if (featureNotYetQueued) { 57 setIsSelected(true); 58 updateQueuedQueryFilters([...queuedQueryFilters, feature]); 59 return; 60 } 61 // if queued and selected, deselect. if queued and not yet selected, don't add or remove 62 if (isSelected) { 63 setIsSelected(false); 64 updateQueuedQueryFilters(filteredFeatures); 65 } 66 } else if (e.ctrlKey || e.metaKey) { 67 openNewQueryWindow(addFeaturesToQueryFilter([feature])); 68 } else { 69 onClick?.(); 70 } 71 72 return false; 73 }; 74 75 const getSelectedClass = (): string => { 76 if (value == null) { 77 return styles.null; 78 } 79 80 if (value.length < 7) { 81 return styles.selectedShort; 82 } else if (value.length < 20) { 83 return styles.selectedMedium; 84 } 85 86 return styles.selectedLong; 87 }; 88 89 const renderValue = (value: string | null) => { 90 // If the value is null, we want the ui to render the string "null". 91 if (value == null) return 'null'; 92 if (isFeatureNameOnly) 93 return ( 94 <Text size={TextSizes.H6} color={TextColors.LIGHT_HEADINGS_PRIMARY} weight={TextWeights.BOLD}> 95 {featureName} 96 </Text> 97 ); 98 if (featureName !== 'ActionName') return value; 99 100 return ( 101 <Text size={TextSizes.H6} color={TextColors.LIGHT_HEADINGS_PRIMARY} weight={TextWeights.BOLD}> 102 {value} 103 </Text> 104 ); 105 }; 106 107 const getFeatureTitle = () => { 108 if (isFeatureNameOnly) return featureName; 109 if (isEntity) return ''; 110 return value ?? 'null'; 111 }; 112 113 return ( 114 <OspreyButton 115 className={classNames(className, { [getSelectedClass()]: isSelected })} 116 style={{ padding: 0 }} 117 onClick={handleFeatureClick} 118 color={value == null ? ButtonColors.LINK_DISABLED : ButtonColors.LINK_BLUE} 119 height={ButtonHeights.SHORT} 120 weight={isEntity ? ButtonWeights.SEMIBOLD : ButtonWeights.NORMAL} 121 title={getFeatureTitle()} 122 textSelectable={textSelectable} 123 > 124 {renderValue(value)} 125 </OspreyButton> 126 ); 127}; 128 129type FeatureProps = CommonFeatureProps & { 130 value: unknown; 131}; 132 133const Feature = ({ value, ...props }: FeatureProps): React.ReactElement => { 134 return <SelectableFeature value={value == null ? null : String(value)} {...props} />; 135}; 136 137export default Feature;