mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:51:43 +00:00
Remove the merged file symbol sidebar (#46499)
This commit is contained in:
parent
57f3ed1db0
commit
3851a2a1dd
@ -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>
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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>
|
||||
)
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
)
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user