import {useCallback, useMemo, useRef} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import {CompactSelect} from 'sentry/components/compactSelect'; import {Alert} from 'sentry/components/core/alert'; import {InputGroup} from 'sentry/components/core/input/inputGroup'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {IconSettings} from 'sentry/icons'; import {IconSearch} from 'sentry/icons/iconSearch'; import {space} from 'sentry/styles/space'; import {useHotkeys} from 'sentry/utils/useHotkeys'; import {useLocation} from 'sentry/utils/useLocation'; import {useNavigate} from 'sentry/utils/useNavigate'; import OrganizationContainer from 'sentry/views/organizationContainer'; import RouteAnalyticsContextProvider from 'sentry/views/routeAnalyticsContextProvider'; import {StoryExports} from 'sentry/views/stories/storyExports'; import {StoryHeader} from 'sentry/views/stories/storyHeader'; import {StoryTableOfContents} from 'sentry/views/stories/storyTableOfContents'; import {StoryTree, useStoryTree} from 'sentry/views/stories/storyTree'; import {useStoriesLoader, useStoryBookFiles} from 'sentry/views/stories/useStoriesLoader'; import {useLocalStorageState} from '../../utils/useLocalStorageState'; export default function Stories() { const searchInput = useRef(null); const location = useLocation<{name: string; query?: string}>(); const files = useStoryBookFiles(); // If no story is selected, show the landing page stories const storyFiles = useMemo(() => { if (!location.query.name) { return files.filter( file => file.endsWith('styles/colors.stories.tsx') || file.endsWith('styles/typography.stories.tsx') ); } return [location.query.name]; }, [files, location.query.name]); const story = useStoriesLoader({files: storyFiles}); const [storyRepresentation, setStoryRepresentation] = useLocalStorageState< 'category' | 'filesystem' >('story-representation', 'category'); const nodes = useStoryTree(files, { query: location.query.query ?? '', representation: storyRepresentation, }); const navigate = useNavigate(); const onSearchInputChange = useCallback( (e: React.ChangeEvent) => { navigate({ query: {...location.query, query: e.target.value, name: location.query.name}, }); }, [location.query, navigate] ); const storiesSearchHotkeys = useMemo(() => { return [{match: '/', callback: () => searchInput.current?.focus()}]; }, []); useHotkeys(storiesSearchHotkeys); return ( {/* @TODO (JonasBadalic): Implement clear button when there is an active query */} {story.isLoading ? ( ) : story.isError ? ( {story.error.name}: {story.error.message} ) : story.isSuccess ? ( {story.data.map(s => { return ; })} ) : ( The file you selected does not export a story. )} ); } function StoryRepresentationToggle(props: { setStoryRepresentation: (value: 'category' | 'filesystem') => void; storyRepresentation: 'category' | 'filesystem'; }) { return ( (