Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(command-bar): various improvements to the command bar #18649

Merged
merged 13 commits into from
Nov 16, 2023
Merged
Binary file modified frontend/__snapshots__/lemon-ui-lemon-skeleton--presets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
return breadcrumbs.length ? (
<div
className="Breadcrumbs3000"
style={

Check warning on line 38 in frontend/src/layout/navigation-3000/components/Breadcrumbs.tsx

View workflow job for this annotation

GitHub Actions / Code quality checks

style should be avoided in favor of utility CSS classes - see https://storybook.posthog.net/?path=/docs/lemon-ui-utilities--overview
{
'--breadcrumbs-compaction-rate': compactionRate,
} as React.CSSProperties
Expand Down Expand Up @@ -124,7 +124,7 @@
function Here({ breadcrumb }: HereProps): JSX.Element {
return (
<h1 className="Breadcrumbs3000__here">
<span>{breadcrumb.name || <LemonSkeleton className="w-40" />}</span>
<span>{breadcrumb.name || <LemonSkeleton className="w-40 h-4" />}</span>
</h1>
)
}
2 changes: 1 addition & 1 deletion frontend/src/lib/components/ActivityLog/ActivityLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const SkeletonLog = (): JSX.Element => {
<div className="activity-log-row items-start">
<LemonSkeleton.Circle />
<div className="details space-y-4 mt-2">
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton />
</div>
</div>
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/lib/components/CommandBar/ActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useValues } from 'kea'

import { actionBarLogic } from './actionBarLogic'

import ActionInput from './ActionInput'
import ActionResults from './ActionResults'
import { ActionInput } from './ActionInput'
import { ActionResults } from './ActionResults'

const ActionBar = (): JSX.Element => {
export const ActionBar = (): JSX.Element => {
const { activeFlow } = useValues(actionBarLogic)

return (
Expand All @@ -15,5 +15,3 @@ const ActionBar = (): JSX.Element => {
</div>
)
}

export default ActionBar
4 changes: 1 addition & 3 deletions frontend/src/lib/components/CommandBar/ActionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const PrefixIcon = ({ activeFlow }: PrefixIconProps): React.ReactElement | null
}
}

const ActionInput = (): JSX.Element => {
export const ActionInput = (): JSX.Element => {
const { input, activeFlow } = useValues(actionBarLogic)
const { setInput } = useActions(actionBarLogic)

Expand All @@ -39,5 +39,3 @@ const ActionInput = (): JSX.Element => {
</div>
)
}

export default ActionInput
4 changes: 1 addition & 3 deletions frontend/src/lib/components/CommandBar/ActionResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type SearchResultProps = {
focused: boolean
}

const ActionResult = ({ result, focused }: SearchResultProps): JSX.Element => {
export const ActionResult = ({ result, focused }: SearchResultProps): JSX.Element => {
const { executeResult, onMouseEnterResult, onMouseLeaveResult } = useActions(actionBarLogic)

const ref = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -51,5 +51,3 @@ const ActionResult = ({ result, focused }: SearchResultProps): JSX.Element => {
</div>
)
}

export default ActionResult
6 changes: 2 additions & 4 deletions frontend/src/lib/components/CommandBar/ActionResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useValues } from 'kea'
import { CommandResultDisplayable } from '../CommandPalette/commandPaletteLogic'

import { actionBarLogic } from './actionBarLogic'
import ActionResult from './ActionResult'
import { ActionResult } from './ActionResult'
import { getNameFromActionScope } from 'lib/components/CommandBar/utils'

type ResultsGroupProps = {
Expand All @@ -27,7 +27,7 @@ const ResultsGroup = ({ scope, results, activeResultIndex }: ResultsGroupProps):
)
}

const ActionResults = (): JSX.Element => {
export const ActionResults = (): JSX.Element => {
const { commandSearchResultsGrouped, activeResultIndex } = useValues(actionBarLogic)

return (
Expand All @@ -38,5 +38,3 @@ const ActionResults = (): JSX.Element => {
</div>
)
}

export default ActionResults
37 changes: 28 additions & 9 deletions frontend/src/lib/components/CommandBar/CommandBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,43 @@ import { commandBarLogic } from './commandBarLogic'
import { BarStatus } from './types'

import './index.scss'
import SearchBar from './SearchBar'
import { LemonModal } from '@posthog/lemon-ui'
import ActionBar from './ActionBar'
import { SearchBar } from './SearchBar'
import { ActionBar } from './ActionBar'

function CommandBar(): JSX.Element | null {
const CommandBarOverlay = ({ children }: { children?: React.ReactNode }): JSX.Element => (
<div
className="fixed top-0 left-0 w-full h-full flex flex-col items-center justify-center p-3"
// eslint-disable-next-line react/forbid-dom-props
style={{
zIndex: 'var(--z-command-palette)',
// background: 'color-mix(in srgb, var(--bg-light) 75%, transparent)',
backgroundColor: 'var(--modal-backdrop-color)',
backdropFilter: 'blur(var(--modal-backdrop-blur))',
}}
>
{children}
</div>
)

export function CommandBar(): JSX.Element | null {
const containerRef = useRef<HTMLDivElement | null>(null)
const { barStatus } = useValues(commandBarLogic)
const { hideCommandBar } = useActions(commandBarLogic)

useOutsideClickHandler(containerRef, hideCommandBar, [])

if (barStatus === BarStatus.HIDDEN) {
return null
}

return (
<LemonModal isOpen={barStatus !== BarStatus.HIDDEN} simple closable={false} width={800}>
<div className="w-full h-160 max-w-lg bg-bg-3000 rounded overflow-hidden flex flex-col" ref={containerRef}>
<CommandBarOverlay>
<div
className="w-full h-160 max-w-lg bg-bg-3000 rounded overflow-hidden flex flex-col border shadow"
ref={containerRef}
>
{barStatus === BarStatus.SHOW_SEARCH ? <SearchBar /> : <ActionBar />}
</div>
</LemonModal>
</CommandBarOverlay>
)
}

export default CommandBar
10 changes: 4 additions & 6 deletions frontend/src/lib/components/CommandBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useMountedLogic } from 'kea'

import { searchBarLogic } from './searchBarLogic'

import SearchInput from './SearchInput'
import SearchResults from './SearchResults'
import SearchTabs from './SearchTabs'
import { SearchInput } from './SearchInput'
import { SearchResults } from './SearchResults'
import { SearchTabs } from './SearchTabs'

const SearchBar = (): JSX.Element => {
export const SearchBar = (): JSX.Element => {
useMountedLogic(searchBarLogic) // load initial results

return (
Expand All @@ -17,5 +17,3 @@ const SearchBar = (): JSX.Element => {
</div>
)
}

export default SearchBar
9 changes: 5 additions & 4 deletions frontend/src/lib/components/CommandBar/SearchBarTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ type SearchBarTabProps = {
count?: number | null
}

const SearchBarTab = ({ type, active, count }: SearchBarTabProps): JSX.Element => {
export const SearchBarTab = ({ type, active, count }: SearchBarTabProps): JSX.Element => {
const { setActiveTab } = useActions(searchBarLogic)
return (
<div className={`px-3 py-2 cursor-pointer text-xs ${active && 'font-bold'}`} onClick={() => setActiveTab(type)}>
<div
className={`px-3 py-2 cursor-pointer text-xs whitespace-nowrap ${active && 'font-bold'}`}
onClick={() => setActiveTab(type)}
>
{resultTypeToName[type]}
{count != null && <span className="ml-1 text-xxs text-muted-3000">{count}</span>}
</div>
)
}

export default SearchBarTab
4 changes: 1 addition & 3 deletions frontend/src/lib/components/CommandBar/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { KeyboardShortcut } from '~/layout/navigation-3000/components/KeyboardSh

import { searchBarLogic } from './searchBarLogic'

const SearchInput = (): JSX.Element => {
export const SearchInput = (): JSX.Element => {
const { searchQuery } = useValues(searchBarLogic)
const { setSearchQuery } = useActions(searchBarLogic)

Expand All @@ -24,5 +24,3 @@ const SearchInput = (): JSX.Element => {
</div>
)
}

export default SearchInput
10 changes: 4 additions & 6 deletions frontend/src/lib/components/CommandBar/SearchResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type SearchResultProps = {
keyboardFocused: boolean
}

const SearchResult = ({ result, resultIndex, focused, keyboardFocused }: SearchResultProps): JSX.Element => {
export const SearchResult = ({ result, resultIndex, focused, keyboardFocused }: SearchResultProps): JSX.Element => {
const { isAutoScrolling } = useValues(searchBarLogic)
const { onMouseEnterResult, onMouseLeaveResult, openResult, setIsAutoScrolling } = useActions(searchBarLogic)

Expand Down Expand Up @@ -76,11 +76,9 @@ const SearchResult = ({ result, resultIndex, focused, keyboardFocused }: SearchR
export const SearchResultSkeleton = (): JSX.Element => (
<div className="w-full pl-3 pr-2 bg-secondary-3000 border-b">
<div className="px-2 py-3 w-full space-y-0.5 flex flex-col items-start">
<LemonSkeleton className="w-32 opacity-75" height={3} />
<LemonSkeleton className="w-80" />
<LemonSkeleton className="w-100 opacity-75" height={3} />
<LemonSkeleton className="w-32 opacity-75 h-3" />
<LemonSkeleton className="w-80 h-4" />
<LemonSkeleton className="w-100 opacity-75 h-3" />
</div>
</div>
)

export default SearchResult
6 changes: 2 additions & 4 deletions frontend/src/lib/components/CommandBar/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { useValues } from 'kea'
import { DetectiveHog } from '../hedgehogs'

import { searchBarLogic } from './searchBarLogic'
import SearchResult, { SearchResultSkeleton } from './SearchResult'
import { SearchResult, SearchResultSkeleton } from './SearchResult'

const SearchResults = (): JSX.Element => {
export const SearchResults = (): JSX.Element => {
const { filterSearchResults, searchResponseLoading, activeResultIndex, keyboardResultIndex } =
useValues(searchBarLogic)

Expand Down Expand Up @@ -38,5 +38,3 @@ const SearchResults = (): JSX.Element => {
</div>
)
}

export default SearchResults
7 changes: 3 additions & 4 deletions frontend/src/lib/components/CommandBar/SearchTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import { useValues } from 'kea'

import { searchBarLogic } from './searchBarLogic'
import SearchBarTab from './SearchBarTab'
import { SearchBarTab } from './SearchBarTab'
import { ResultType } from './types'

const SearchTabs = (): JSX.Element | null => {
export const SearchTabs = (): JSX.Element | null => {
const { searchResponse, activeTab } = useValues(searchBarLogic)

if (!searchResponse) {
return null
}

return (
<div className="flex items-center border-t space-x-3 px-2">
<div className="flex items-center border-t space-x-3 px-2 shrink-0 overflow-x-auto">
<SearchBarTab type="all" active={activeTab === 'all'} />
{Object.entries(searchResponse.counts).map(([type, count]) => (
<SearchBarTab key={type} type={type as ResultType} count={count} active={activeTab === type} />
))}
</div>
)
}
export default SearchTabs
2 changes: 1 addition & 1 deletion frontend/src/lib/components/CommandBar/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const resultTypeToName: Record<ResultTypeWithAll, string> = {
cohort: 'Cohorts',
dashboard: 'Dashboards',
experiment: 'Experiments',
feature_flag: 'Feature Flags',
feature_flag: 'Feature flags',
insight: 'Insights',
}

Expand Down
10 changes: 8 additions & 2 deletions frontend/src/lib/components/CommandBar/searchBarLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,14 @@ export const searchBarLogic = kea<searchBarLogicType>([
// hide command bar
actions.hideCommandBar()
} else if (event.key === '>') {
if (values.searchQuery.length === 0) {
// transition to actions when entering '>' with empty input
const { value, selectionStart, selectionEnd } = event.target as HTMLInputElement
if (
values.searchQuery.length === 0 ||
(selectionStart !== null &&
selectionEnd !== null &&
(value.substring(0, selectionStart) + value.substring(selectionEnd)).length === 0)
) {
// transition to actions when entering '>' with empty input, or when replacing the whole input
event.preventDefault()
actions.setCommandBar(BarStatus.SHOW_ACTIONS)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import squeakFile from 'public/squeak.mp3'
import './CommandPalette.scss'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { FEATURE_FLAGS } from 'lib/constants'
import CommandBar from '../CommandBar/CommandBar'
import { CommandBar } from '../CommandBar/CommandBar'

/** Use the new Cmd+K search when the respective feature flag is enabled. */
export function CommandPalette(): JSX.Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ export function EditSubscription({
{!subscription ? (
subscriptionLoading ? (
<div className="space-y-4">
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton.Row />
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton.Row />
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton.Row />
</div>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export function ManageSubscriptions({
<LemonModal.Content>
{subscriptionsLoading && !subscriptions.length ? (
<div className="space-y-2">
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton.Row repeat={2} />
</div>
) : subscriptions.length ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function Presets(): JSX.Element {
}
>
<div className="space-y-2">
<LemonSkeleton className="w-1/2" />
<LemonSkeleton className="w-1/2 h-4" />
<LemonSkeleton.Row repeat={3} />
</div>
</LemonModal>
Expand Down
18 changes: 2 additions & 16 deletions frontend/src/lib/lemon-ui/LemonSkeleton/LemonSkeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,15 @@ import './LemonSkeleton.scss'

export interface LemonSkeletonProps {
className?: string
/** Height of the skeleton bar */
height?: number
/** Repeat this component this many of times */
repeat?: number
/** Used in combination with repeat to progressively fade out the repeated skeletons */
fade?: boolean
active?: boolean
}
export function LemonSkeleton({
className,
repeat,
height = 4,
active = true,
fade = false,
}: LemonSkeletonProps): JSX.Element {
export function LemonSkeleton({ className, repeat, active = true, fade = false }: LemonSkeletonProps): JSX.Element {
const content = (
<div
className={clsx(
`LemonSkeleton rounded h-${height}`,
!active && 'LemonSkeleton--static',
className || 'w-full'
)}
>
<div className={clsx('LemonSkeleton rounded', !active && 'LemonSkeleton--static', className || 'h-4 w-full')}>
{/* The span is for accessibility, but also because @storybook/test-runner smoke tests require content */}
<span>Loading…</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/apps/ErrorDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function ErrorDetailsModal(): JSX.Element {
footer={
<div className="flex items-center justify-end gap-1 h-">
{errorDetailsLoading ? (
<LemonSkeleton className="1-10" />
<LemonSkeleton className="h-10" />
) : (
<>
<span>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/apps/MetricsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function MetricsOverview({
exportFailureReason,
}: MetricsOverviewProps): JSX.Element {
if (metricsLoading) {
return <LemonSkeleton className="w-20 mb-2" repeat={4} />
return <LemonSkeleton className="w-20 h-4 mb-2" repeat={4} />
}

return (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/batch_exports/BatchExportScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ export function BatchExportScene(): JSX.Element {
</div>
</>
) : (
<LemonSkeleton className="w-10" />
<LemonSkeleton className="w-10 h-4" />
)}
</div>

Expand Down
Loading
Loading