Remove the merged file symbol sidebar (#46499)

This commit is contained in:
Philipp Spiess 2023-01-16 12:43:26 +01:00 committed by GitHub
parent 57f3ed1db0
commit 3851a2a1dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 14 additions and 252 deletions

View File

@ -4,7 +4,6 @@ import { mdiChevronDoubleRight, mdiChevronDoubleLeft } from '@mdi/js'
import classNames from 'classnames'
import * as H from 'history'
import { isErrorLike } from '@sourcegraph/common'
import { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
@ -60,12 +59,6 @@ export const RepoRevisionSidebar: React.FunctionComponent<
const isWideScreen = useMatchMedia('(min-width: 768px)', false)
const [isVisible, setIsVisible] = useState(persistedIsVisible && isWideScreen)
const enableMergedFileSymbolSidebar =
props.settingsCascade.final &&
!isErrorLike(props.settingsCascade.final) &&
props.settingsCascade.final.experimentalFeatures &&
props.settingsCascade.final.experimentalFeatures.enableMergedFileSymbolSidebar
const handleSidebarToggle = useCallback(
(value: boolean) => {
props.telemetryService.log('FileTreeViewClicked', {
@ -109,13 +102,9 @@ export const RepoRevisionSidebar: React.FunctionComponent<
isAuthenticated={!!props.authenticatedUser}
isSourcegraphDotCom={props.isSourcegraphDotCom}
/>
{/* `key` is used to force rerendering the Tabs component when the UI
setting changes. This is necessary to force registering Tabs and
TabPanels properly. */}
<Tabs
key={`ui-${enableMergedFileSymbolSidebar}`}
className="w-100 test-repo-revision-sidebar pr-3 h-25 d-flex flex-column flex-grow-1"
defaultIndex={enableMergedFileSymbolSidebar ? 0 : persistedTabIndex}
defaultIndex={persistedTabIndex}
onChange={setPersistedTabIndex}
lazy={true}
>
@ -139,11 +128,9 @@ export const RepoRevisionSidebar: React.FunctionComponent<
<Tab data-tab-content="files">
<span className="tablist-wrapper--tab-label">Files</span>
</Tab>
{!enableMergedFileSymbolSidebar && (
<Tab data-tab-content="symbols">
<span className="tablist-wrapper--tab-label">Symbols</span>
</Tab>
)}
<Tab data-tab-content="symbols">
<span className="tablist-wrapper--tab-label">Symbols</span>
</Tab>
</TabList>
<div className={classNames('flex w-100 overflow-auto explorer', styles.tabpanels)} tabIndex={-1}>
{/* TODO: See if we can render more here, instead of waiting for these props */}
@ -162,20 +149,17 @@ export const RepoRevisionSidebar: React.FunctionComponent<
activePathIsDir={props.isDir}
sizeKey={`Resizable:${SIZE_STORAGE_KEY}`}
telemetryService={props.telemetryService}
enableMergedFileSymbolSidebar={!!enableMergedFileSymbolSidebar}
/>
</TabPanel>
{!enableMergedFileSymbolSidebar && (
<TabPanel>
<RepoRevisionSidebarSymbols
key="symbols"
repoID={props.repoID}
revision={props.revision}
activePath={props.filePath}
onHandleSymbolClick={handleSymbolClick}
/>
</TabPanel>
)}
<TabPanel>
<RepoRevisionSidebarSymbols
key="symbols"
repoID={props.repoID}
revision={props.revision}
activePath={props.filePath}
onHandleSymbolClick={handleSymbolClick}
/>
</TabPanel>
</TabPanels>
)}
</div>

View File

@ -19,7 +19,6 @@ interface ChildTreeLayerProps extends Omit<TreeRootProps, 'sizeKey'> {
singleChildTreeEntry: SingleChildGitTree
/** The children entries of a SingleChildTreeLayer. Will be undefined if there is no SingleChildTreeLayer to render. */
childrenEntries?: SingleChildGitTree[]
enableMergedFileSymbolSidebar: boolean
onHover: (filePath: string) => void
}
@ -79,7 +78,6 @@ export const ChildTreeLayer: React.FunctionComponent<React.PropsWithChildren<Chi
isSelected={false}
isGoUpTreeLink={true}
customIconPath={mdiFolderOutline}
enableMergedFileSymbolSidebar={props.enableMergedFileSymbolSidebar}
/>
)}
</TreeRootContext.Consumer>
@ -100,7 +98,6 @@ export const ChildTreeLayer: React.FunctionComponent<React.PropsWithChildren<Chi
entryInfo={props.singleChildTreeEntry}
childrenEntries={props.singleChildTreeEntry.children}
telemetryService={props.telemetryService}
enableMergedFileSymbolSidebar={props.enableMergedFileSymbolSidebar}
/>
) : (
props.entries.map((item, index) => (
@ -112,7 +109,6 @@ export const ChildTreeLayer: React.FunctionComponent<React.PropsWithChildren<Chi
parentPath={item.path}
entryInfo={item}
telemetryService={props.telemetryService}
enableMergedFileSymbolSidebar={props.enableMergedFileSymbolSidebar}
/>
))
)}

View File

@ -1,34 +0,0 @@
.symbols {
background-color: var(--color-bg-2);
color: var(--gray-06);
ul {
width: 100%;
list-style: none;
padding: 0;
margin: 0;
// Used to prevent margin collapse
display: flex;
flex-direction: column;
li {
margin: 0.25rem 0;
}
}
.link {
display: block;
padding: 0.25rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&--active,
&:hover {
background-color: var(--color-bg-3);
text-decoration: none;
color: var(--body-color);
border-radius: var(--border-radius);
}
}
}

View File

@ -1,22 +1,13 @@
/* eslint jsx-a11y/click-events-have-key-events: warn, jsx-a11y/no-static-element-interactions: warn */
import * as React from 'react'
import { useEffect, useState } from 'react'
import { mdiSourceRepository, mdiFileDocumentOutline } from '@mdi/js'
import classNames from 'classnames'
import * as H from 'history'
import { escapeRegExp, isEqual } from 'lodash'
import { NavLink, useLocation } from 'react-router-dom'
import { gql, useQuery } from '@sourcegraph/http-client'
import { PrefetchableFile } from '@sourcegraph/shared/src/components/PrefetchableFile'
import { SymbolKind } from '@sourcegraph/shared/src/symbols/SymbolKind'
import { Icon, LoadingSpinner } from '@sourcegraph/wildcard'
import { Icon } from '@sourcegraph/wildcard'
import { InlineSymbolsResult } from '../graphql-operations'
import { fetchBlob, usePrefetchBlobFormat } from '../repo/blob/backend'
import { useExperimentalFeatures } from '../stores'
import { parseBrowserRepoURL } from '../util/url'
import {
TreeLayerCell,
@ -30,10 +21,8 @@ import {
} from './components'
import { MAX_TREE_ENTRIES } from './constants'
import { useTreeRootContext } from './TreeContext'
import { TreeLayerProps } from './TreeLayer'
import { TreeEntryInfo, getTreeItemOffset } from './util'
import styles from './File.module.scss'
import treeStyles from './Tree.module.scss'
interface FileProps {
@ -47,7 +36,6 @@ interface FileProps {
isActive: boolean
isSelected: boolean
customIconPath?: string
enableMergedFileSymbolSidebar: boolean
isGoUpTreeLink?: boolean
}
@ -62,7 +50,6 @@ export const File: React.FunctionComponent<React.PropsWithChildren<FileProps>> =
noopRowClick,
depth,
index,
enableMergedFileSymbolSidebar,
customIconPath,
} = props
@ -154,155 +141,6 @@ export const File: React.FunctionComponent<React.PropsWithChildren<FileProps>> =
)}
</TreeLayerCell>
</TreeRow>
{enableMergedFileSymbolSidebar && isActive && <Symbols activePath={entryInfo.path} style={offsetStyle} />}
</>
)
}
export const SYMBOLS_QUERY = gql`
query InlineSymbols($repo: ID!, $revision: String!, $includePatterns: [String!]) {
node(id: $repo) {
__typename
... on Repository {
commit(rev: $revision) {
symbols(first: 1000, query: "", includePatterns: $includePatterns) {
...InlineSymbolConnectionFields
}
}
}
}
}
fragment InlineSymbolConnectionFields on SymbolConnection {
__typename
nodes {
...InlineSymbolNodeFields
}
}
fragment InlineSymbolNodeFields on Symbol {
__typename
name
containerName
kind
language
location {
resource {
path
}
range {
start {
line
character
}
end {
line
character
}
}
}
url
}
`
interface SymbolsProps
extends Pick<TreeLayerProps, 'activePath'>,
Pick<React.HTMLAttributes<HTMLDivElement>, 'style'> {}
const Symbols: React.FunctionComponent<SymbolsProps> = ({ activePath, style }) => {
const location = useLocation()
const { repoID, revision } = useTreeRootContext()
const { data, loading, error } = useQuery<InlineSymbolsResult>(SYMBOLS_QUERY, {
variables: {
repo: repoID,
revision,
// `includePatterns` expects regexes, so first escape the path.
includePatterns: ['^' + escapeRegExp(activePath)],
},
})
const currentLocation = parseBrowserRepoURL(H.createPath(location))
const isSymbolActive = (symbolUrl: string): boolean => {
const symbolLocation = parseBrowserRepoURL(symbolUrl)
return (
currentLocation.repoName === symbolLocation.repoName &&
currentLocation.revision === symbolLocation.revision &&
currentLocation.filePath === symbolLocation.filePath &&
isEqual(currentLocation.position, symbolLocation.position)
)
}
const symbolKindTags = useExperimentalFeatures(features => features.symbolKindTags)
if (loading) {
return (
<Delay timeout={800}>
<TreeRow className={styles.symbols}>
<TreeLayerCell>
<TreeLayerRowContents className="d-flex" style={style}>
<LoadingSpinner /> Loading symbol data...
</TreeLayerRowContents>
</TreeLayerCell>
</TreeRow>
</Delay>
)
}
let content = null
if (error) {
content = 'Unable to load symbol data.'
}
if (data && data.node?.__typename === 'Repository') {
// Only consider top-level symbols
const symbols = data.node.commit?.symbols.nodes.filter(symbol => !symbol.containerName) ?? []
if (symbols.length > 0) {
content = (
<ul>
{symbols.map(symbol => (
<li key={symbol.url}>
<NavLink
to={symbol.url}
isActive={() => isSymbolActive(symbol.url)}
className={classNames('test-symbol-link', styles.link)}
activeClassName={styles.linkActive}
>
<SymbolKind
kind={symbol.kind}
className="mr-1 test-symbol-icon"
symbolKindTags={symbolKindTags}
/>
<span className={classNames('test-symbol-name')}>{symbol.name}</span>
</NavLink>
</li>
))}
</ul>
)
} else {
content = 'No symbols found.'
}
}
if (content) {
return (
<TreeRow className={styles.symbols}>
<TreeLayerCell>
<TreeLayerRowContents style={style}>{content}</TreeLayerRowContents>
</TreeLayerCell>
</TreeRow>
)
}
return null
}
const Delay: React.FunctionComponent<{ timeout: number; children: React.ReactElement }> = ({ timeout, children }) => {
const [show, setShow] = useState(false)
useEffect(() => {
const id = setTimeout(() => setShow(true), timeout)
return () => clearTimeout(id)
}, [timeout])
return show ? children : null
}

View File

@ -31,7 +31,6 @@ interface Props extends AbsoluteRepo, TelemetryProps {
/** The localStorage key that stores the current size of the (resizable) RepoRevisionSidebar. */
sizeKey: string
repoID: Scalars['ID']
enableMergedFileSymbolSidebar: boolean
}
interface State {
@ -341,7 +340,6 @@ export class Tree extends React.PureComponent<Props, State> {
setActiveNode={this.setActiveNode}
sizeKey={this.props.sizeKey}
telemetryService={this.props.telemetryService}
enableMergedFileSymbolSidebar={this.props.enableMergedFileSymbolSidebar}
/>
</div>
)

View File

@ -40,7 +40,6 @@ export interface TreeLayerProps extends Omit<TreeRootProps, 'sizeKey'> {
entryInfo: TreeEntryInfo
onHover: (filePath: string) => void
repoID: Scalars['ID']
enableMergedFileSymbolSidebar: boolean
}
const LOADING = 'loading' as const
@ -278,9 +277,6 @@ export class TreeLayer extends React.Component<TreeLayerProps, TreeLayerState> {
singleChildTreeEntry={singleChildTreeEntry}
childrenEntries={singleChildTreeEntry.children}
setChildNodes={this.setChildNode}
enableMergedFileSymbolSidebar={
this.props.enableMergedFileSymbolSidebar
}
/>
)
)}
@ -298,7 +294,6 @@ export class TreeLayer extends React.Component<TreeLayerProps, TreeLayerState> {
linkRowClick={this.linkRowClick}
isActive={isActive}
isSelected={isSelected}
enableMergedFileSymbolSidebar={this.props.enableMergedFileSymbolSidebar}
/>
)}
</tbody>

View File

@ -53,7 +53,6 @@ export interface TreeRootProps extends AbsoluteRepo, TelemetryProps {
setChildNodes: (node: TreeNode, index: number) => void
setActiveNode: (node: TreeNode) => void
repoID: Scalars['ID']
enableMergedFileSymbolSidebar: boolean
}
const LOADING = 'loading' as const
@ -200,9 +199,6 @@ export class TreeRoot extends React.Component<TreeRootProps, TreeRootState> {
childrenEntries={singleChildTreeEntry.children}
onHover={this.fetchChildContents}
setChildNodes={this.setChildNode}
enableMergedFileSymbolSidebar={
this.props.enableMergedFileSymbolSidebar
}
/>
</TreeRootContext.Provider>
)

View File

@ -2052,8 +2052,6 @@ type SettingsExperimentalFeatures struct {
EnableLazyBlobSyntaxHighlighting *bool `json:"enableLazyBlobSyntaxHighlighting,omitempty"`
// EnableLazyFileResultSyntaxHighlighting description: Fetch un-highlighted file result contents to render immediately, decorate with syntax highlighting once loaded.
EnableLazyFileResultSyntaxHighlighting *bool `json:"enableLazyFileResultSyntaxHighlighting,omitempty"`
// EnableMergedFileSymbolSidebar description: Enables the new file sidebar experience with merged file and symbol entries.
EnableMergedFileSymbolSidebar *bool `json:"enableMergedFileSymbolSidebar,omitempty"`
// EnableSearchFilePrefetch description: Pre-fetch plaintext file revisions from search results on hover/focus.
EnableSearchFilePrefetch *bool `json:"enableSearchFilePrefetch,omitempty"`
// EnableSidebarFilePrefetch description: Pre-fetch plaintext file revisions from sidebar on hover/focus.
@ -2154,7 +2152,6 @@ func (v *SettingsExperimentalFeatures) UnmarshalJSON(data []byte) error {
delete(m, "enableGoImportsSearchQueryTransform")
delete(m, "enableLazyBlobSyntaxHighlighting")
delete(m, "enableLazyFileResultSyntaxHighlighting")
delete(m, "enableMergedFileSymbolSidebar")
delete(m, "enableSearchFilePrefetch")
delete(m, "enableSidebarFilePrefetch")
delete(m, "fuzzyFinder")

View File

@ -129,14 +129,6 @@
"pointer": true
}
},
"enableMergedFileSymbolSidebar": {
"description": "Enables the new file sidebar experience with merged file and symbol entries.",
"type": "boolean",
"default": false,
"!go": {
"pointer": true
}
},
"codeNavigation": {
"description": "What kind of experimental code navigation UX to enable. The most recommended option is 'selection-driven'.",
"type": "string",