| 11 | import { usePersistedState } from './usePersistentState'; |
| 12 | |
| 13 | export const SourceExplorer: FunctionComponent = () => { |
| 14 | const dump = useDump(); |
| 15 | |
| 16 | const uniqueIdMap = useMemo(() => { |
| 17 | const map = new Map<number, IDiagnosticSource>(); |
| 18 | for (const source of dump.sources) { |
| 19 | map.set(source.uniqueId, source); |
| 20 | } |
| 21 | return map; |
| 22 | }, [dump.sources]); |
| 23 | |
| 24 | const indexed = useMemo( |
| 25 | () => |
| 26 | dump.sources |
| 27 | .map( |
| 28 | source => |
| 29 | [ |
| 30 | [source.url, source.absolutePath, source.prettyName].join(' ').toLowerCase(), |
| 31 | source, |
| 32 | ] as [string, IDiagnosticSource], |
| 33 | ) |
| 34 | .sort((a, b) => sortScore(a[1]) - sortScore(b[1])), |
| 35 | [dump.sources], |
| 36 | ); |
| 37 | |
| 38 | const [filter, setFilter] = usePersistedState('filter', ''); |
| 39 | const results = useMemo( |
| 40 | () => |
| 41 | filter |
| 42 | ? indexed.filter(([str]) => str.includes(filter.toLowerCase())).map(([, src]) => src) |
| 43 | : indexed.map(i => i[1]), |
| 44 | [indexed, filter], |
| 45 | ); |
| 46 | const onChange = useCallback( |
| 47 | (evt: Event) => setFilter((evt.target as HTMLInputElement).value), |
| 48 | [], |
| 49 | ); |
| 50 | |
| 51 | return ( |
| 52 | <Fragment> |
| 53 | <input |
| 54 | placeholder='Filter sources...' |
| 55 | className='source-filter' |
| 56 | value={filter} |
| 57 | onChange={onChange} |
| 58 | onKeyUp={onChange} |
| 59 | /> |
| 60 | <small style={{ marginBottom: '1rem' }}> |
| 61 | Showing {results.length} of {dump.sources.length} sources... |
| 62 | </small> |
| 63 | {results.map(result => ( |
| 64 | <Source source={result} allSources={uniqueIdMap} key={result.sourceReference} /> |
| 65 | ))} |
| 66 | </Fragment> |
| 67 | ); |
| 68 | }; |
| 69 | |
| 70 | export const Source: FunctionComponent<{ |