remove disabled web UI code for embeddings (#63432)

Repository embeddings were removed in Feb 2024 as part of the Cody
Enterprise GA. They have not been used since. Some Sourcegraph instances
still running an older pre-GA version may still rely on Cody Gateway
(deployed by us) for embeddings generation, but they do not rely on this
UI code at all, so it is safe to remove.

No changelog entry needed since this code's UI has been disabled since
Feb 2024.

## Test plan

Existing tests suffice since this is removing functionality.
This commit is contained in:
Quinn Slack 2024-06-24 08:38:09 -07:00 committed by GitHub
parent 8b6d4f8513
commit 896819f811
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 55 additions and 1230 deletions

View File

@ -79,7 +79,7 @@ export default defineConfig(({ mode }) => {
proxy: {
// Proxy requests to specific endpoints to a real Sourcegraph
// instance.
'^(/sign-in|/.assets|/-|/.api|/search/stream|/users|/notebooks|/insights|/batch-changes)|/-/(raw|compare|own|embeddings|code-graph|batch-changes|settings)(/|$)':
'^(/sign-in|/.assets|/-|/.api|/search/stream|/users|/notebooks|/insights|/batch-changes)|/-/(raw|compare|own|code-graph|batch-changes|settings)(/|$)':
{
target: process.env.SOURCEGRAPH_API_URL || 'https://sourcegraph.com',
changeOrigin: true,

View File

@ -736,10 +736,6 @@ ts_project(
"src/enterprise/codeintel/sort.ts",
"src/enterprise/codeintel/useCodeIntel.ts",
"src/enterprise/codeintel/useSearchBasedCodeIntel.ts",
"src/enterprise/cody/configuration/components/EmptyPoliciesList.tsx",
"src/enterprise/cody/configuration/pages/CodyConfigurationPage.tsx",
"src/enterprise/cody/repo/CodyRepoArea.tsx",
"src/enterprise/cody/repo/CodyRepoSidebar.tsx",
"src/enterprise/dotcom/productSubscriptions/AccountName.tsx",
"src/enterprise/dotcom/productSubscriptions/ProductLicenseValidity.tsx",
"src/enterprise/dotcom/productSubscriptions/ProductSubscriptionLabel.tsx",
@ -1070,9 +1066,6 @@ ts_project(
"src/enterprise/site-admin/UserManagement/backend.ts",
"src/enterprise/site-admin/UserManagement/components/RoleAssignmentModal.tsx",
"src/enterprise/site-admin/backend.ts",
"src/enterprise/site-admin/cody/RepoEmbeddingJobNode.tsx",
"src/enterprise/site-admin/cody/SiteAdminCodyPage.tsx",
"src/enterprise/site-admin/cody/backend.ts",
"src/enterprise/site-admin/dotcom/customers/SiteAdminCustomersPage.tsx",
"src/enterprise/site-admin/dotcom/productSubscriptions/CodyGatewayRateLimitModal.tsx",
"src/enterprise/site-admin/dotcom/productSubscriptions/CodyServicesSection.tsx",
@ -1392,7 +1385,6 @@ ts_project(
"src/repo/releases/RepositoryReleasesTagsPage.tsx",
"src/repo/repoContainerRoutes.tsx",
"src/repo/repoRevisionContainerRoutes.tsx",
"src/repo/repoRevisionSidebar/cody/backend.tsx",
"src/repo/settings/RepoSettingsArea.tsx",
"src/repo/settings/RepoSettingsIndexPage.tsx",
"src/repo/settings/RepoSettingsMirrorPage.tsx",

View File

@ -87,7 +87,6 @@ export const createJsContext = ({ sourcegraphBaseUrl }: { sourcegraphBaseUrl: st
endpoint: ENVIRONMENT_CONFIG.CLIENT_OTEL_EXPORTER_OTLP_ENDPOINT,
},
telemetryRecorder: noOpTelemetryRecorder,
embeddingsEnabled: false,
primaryLoginProvidersCount: 5,
// Site-config overrides default JS context
...siteConfig,

View File

@ -114,9 +114,6 @@
.repo-icon {
color: var(--text-disabled);
}
.embedding-icon-no-embeddings {
color: var(--gray-07);
}
}
.not-included-in-context:hover {

View File

@ -10,5 +10,3 @@ export const isCodyEnabled = (): boolean => {
}
export const isSignInRequiredForCody = (): boolean => !window.context.isAuthenticatedUser
export const isEmbeddingsEnabled = (): boolean => window.context?.codyEnabled && window.context?.embeddingsEnabled

View File

@ -24,7 +24,6 @@ export const POLICIES_CONFIGURATION = gql`
$query: String
$forDataRetention: Boolean
$forIndexing: Boolean
$forEmbeddings: Boolean
$first: Int
$after: String
$protected: Boolean
@ -34,7 +33,6 @@ export const POLICIES_CONFIGURATION = gql`
query: $query
forDataRetention: $forDataRetention
forIndexing: $forIndexing
forEmbeddings: $forEmbeddings
first: $first
after: $after
protected: $protected
@ -60,7 +58,6 @@ export const queryPolicies = (
query,
forDataRetention,
forIndexing,
forEmbeddings,
after,
protected: varProtected,
}: Partial<CodeIntelligenceConfigurationPoliciesVariables>,
@ -71,7 +68,6 @@ export const queryPolicies = (
query: query ?? null,
forDataRetention: forDataRetention ?? null,
forIndexing: forIndexing ?? null,
forEmbeddings: forEmbeddings ?? null,
first: first ?? null,
after: after ?? null,
protected: varProtected ?? null,

View File

@ -16,7 +16,6 @@ export const nullPolicy = {
indexingEnabled: false,
indexCommitMaxAgeHours: null,
indexIntermediateCommits: false,
embeddingsEnabled: false,
repository: null,
}
@ -39,6 +38,5 @@ export const defaultCodeIntelligenceConfigurationPolicyFieldsFragment = gql`
indexingEnabled
indexCommitMaxAgeHours
indexIntermediateCommits
embeddingsEnabled
}
`

View File

@ -41,7 +41,6 @@ const emptyPolicy: CodeIntelligenceConfigurationPolicyFields = {
indexingEnabled: false,
indexCommitMaxAgeHours: null,
indexIntermediateCommits: false,
embeddingsEnabled: false,
}
export const usePolicyConfigurationByID = (id: string): UsePolicyConfigResult => {

View File

@ -17,7 +17,6 @@ const CREATE_POLICY_CONFIGURATION = gql`
$indexingEnabled: Boolean!
$indexCommitMaxAgeHours: Int
$indexIntermediateCommits: Boolean!
$embeddingsEnabled: Boolean!
) {
createCodeIntelligenceConfigurationPolicy(
repository: $repositoryId
@ -31,7 +30,6 @@ const CREATE_POLICY_CONFIGURATION = gql`
indexingEnabled: $indexingEnabled
indexCommitMaxAgeHours: $indexCommitMaxAgeHours
indexIntermediateCommits: $indexIntermediateCommits
embeddingsEnabled: $embeddingsEnabled
) {
id
}
@ -51,7 +49,6 @@ const UPDATE_POLICY_CONFIGURATION = gql`
$indexingEnabled: Boolean!
$indexCommitMaxAgeHours: Int
$indexIntermediateCommits: Boolean!
$embeddingsEnabled: Boolean!
) {
updateCodeIntelligenceConfigurationPolicy(
id: $id
@ -65,7 +62,6 @@ const UPDATE_POLICY_CONFIGURATION = gql`
indexingEnabled: $indexingEnabled
indexCommitMaxAgeHours: $indexCommitMaxAgeHours
indexIntermediateCommits: $indexIntermediateCommits
embeddingsEnabled: $embeddingsEnabled
) {
alwaysNil
}

View File

@ -1,4 +1,4 @@
import React, { type FunctionComponent, useCallback, useEffect, useMemo } from 'react'
import React, { useCallback, useEffect, useMemo, type FunctionComponent } from 'react'
import { useApolloClient } from '@apollo/client'
import {
@ -11,10 +11,9 @@ import {
mdiLock,
mdiPencil,
mdiSourceRepository,
mdiVectorPolyline,
} from '@mdi/js'
import classNames from 'classnames'
import { useNavigate, useLocation } from 'react-router-dom'
import { useLocation, useNavigate } from 'react-router-dom'
import { Subject } from 'rxjs'
import { RepoLink } from '@sourcegraph/shared/src/components/RepoLink'
@ -69,12 +68,12 @@ export const CodeIntelConfigurationPage: FunctionComponent<CodeIntelConfiguratio
const apolloClient = useApolloClient()
const queryDefaultPoliciesCallback = useCallback(
(args: FilteredConnectionQueryArguments) =>
queryPolicies({ ...args, repository: repo?.id, forEmbeddings: false, protected: true }, apolloClient),
queryPolicies({ ...args, repository: repo?.id, protected: true }, apolloClient),
[queryPolicies, repo?.id, apolloClient]
)
const queryCustomPoliciesCallback = useCallback(
(args: FilteredConnectionQueryArguments) =>
queryPolicies({ ...args, repository: repo?.id, forEmbeddings: false, protected: false }, apolloClient),
queryPolicies({ ...args, repository: repo?.id, protected: false }, apolloClient),
[queryPolicies, repo?.id, apolloClient]
)
@ -222,7 +221,6 @@ export const CodeIntelConfigurationPage: FunctionComponent<CodeIntelConfiguratio
interface ProtectedPoliciesNodeProps {
node: CodeIntelligenceConfigurationPolicyFields
indexingEnabled?: boolean
domain?: 'scip' | 'embeddings'
}
export interface UnprotectedPoliciesNodeProps {
@ -230,7 +228,6 @@ export interface UnprotectedPoliciesNodeProps {
isDeleting: boolean
onDelete: (id: string, name: string) => Promise<void>
indexingEnabled?: boolean
domain?: 'scip' | 'embeddings'
}
type PoliciesNodeProps = ProtectedPoliciesNodeProps | UnprotectedPoliciesNodeProps
@ -238,28 +235,24 @@ type PoliciesNodeProps = ProtectedPoliciesNodeProps | UnprotectedPoliciesNodePro
export const PoliciesNode: FunctionComponent<React.PropsWithChildren<PoliciesNodeProps>> = ({
node: policy,
indexingEnabled = false,
domain = 'scip',
...props
}) => (
<>
<span className={styles.separator} />
<div className={classNames(styles.name, 'd-flex flex-column')}>
<PolicyDescription policy={policy} indexingEnabled={indexingEnabled} domain={domain} />
<PolicyDescription policy={policy} indexingEnabled={indexingEnabled} />
<RepositoryAndGitObjectDescription policy={policy} />
{policy.indexingEnabled && indexingEnabled && <AutoIndexingDescription policy={policy} />}
{policy.retentionEnabled && <RetentionDescription policy={policy} />}
{policy.embeddingsEnabled && <EmbeddingsDescription policy={policy} />}
</div>
<div className="h-100">
<Link
to={
policy.repository === null
? `/site-admin/${domain === 'scip' ? 'code-graph' : 'embeddings'}/configuration/${policy.id}`
: `/${policy.repository.name}/-/${
domain === 'scip' ? 'code-graph' : 'embeddings'
}/configuration/${policy.id}`
? `/site-admin/code-graph/configuration/${policy.id}`
: `/${policy.repository.name}/-/code-graph/configuration/${policy.id}`
}
>
<Tooltip content="Edit this policy">
@ -299,23 +292,19 @@ interface PolicyDescriptionProps {
policy: CodeIntelligenceConfigurationPolicyFields
indexingEnabled?: boolean
allowGlobalPolicies?: boolean
domain?: 'scip' | 'embeddings'
}
const PolicyDescription: FunctionComponent<PolicyDescriptionProps> = ({
policy,
indexingEnabled = false,
allowGlobalPolicies = window.context?.codeIntelAutoIndexingAllowGlobalPolicies,
domain = 'scip',
}) => (
<div className={styles.policyDescription}>
<Link
to={
policy.repository === null
? `/site-admin/${domain === 'scip' ? 'code-graph' : 'embeddings'}/configuration/${policy.id}`
: `/${policy.repository.name}/-/${domain === 'scip' ? 'code-graph' : 'embeddings'}/configuration/${
policy.id
}`
? `/site-admin/code-graph/configuration/${policy.id}`
: `/${policy.repository.name}/-/code-graph/configuration/${policy.id}`
}
>
<Text weight="bold" className="mb-0">
@ -323,7 +312,7 @@ const PolicyDescription: FunctionComponent<PolicyDescriptionProps> = ({
</Text>
</Link>
{!policy.retentionEnabled && !(indexingEnabled && policy.indexingEnabled) && !policy.embeddingsEnabled && (
{!policy.retentionEnabled && !(indexingEnabled && policy.indexingEnabled) && (
<Tooltip content="This policy has no enabled behaviors.">
<Icon
svgPath={mdiCircleOffOutline}
@ -540,22 +529,3 @@ const RetentionDescription: FunctionComponent<RetentionDescriptionProps> = ({ po
</span>
</div>
)
interface EmbeddingsDescriptionProps {
policy: CodeIntelligenceConfigurationPolicyFields
}
const EmbeddingsDescription: FunctionComponent<EmbeddingsDescriptionProps> = ({ policy }) => (
<div>
<Tooltip content="This policy affects embeddings.">
<Icon
svgPath={mdiVectorPolyline}
inline={true}
aria-label="This policy affects embeddings."
className="mr-2"
/>
</Tooltip>
<span>Maintains embeddings.</span>
</div>
)

View File

@ -1,10 +1,10 @@
import { type FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState, type FunctionComponent } from 'react'
import type { ApolloError } from '@apollo/client'
import { mdiCheck, mdiDelete, mdiGraveStone } from '@mdi/js'
import { mdiDelete, mdiGraveStone } from '@mdi/js'
import classNames from 'classnames'
import { debounce } from 'lodash'
import { useNavigate, useParams, useLocation } from 'react-router-dom'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import { Toggle } from '@sourcegraph/branded/src/components/Toggle'
import { useLazyQuery } from '@sourcegraph/http-client'
@ -46,8 +46,8 @@ import { useDeletePolicies } from '../hooks/useDeletePolicies'
import { usePolicyConfigurationByID } from '../hooks/usePolicyConfigurationById'
import {
convertGitObjectFilterResult,
type GitObjectPreviewResult,
PREVIEW_GIT_OBJECT_FILTER,
type GitObjectPreviewResult,
} from '../hooks/usePreviewGitObjectFilter'
import { useSavePolicyConfiguration } from '../hooks/useSavePolicyConfiguration'
import { hasGlobalPolicyViolation } from '../shared'
@ -63,7 +63,6 @@ export interface CodeIntelConfigurationPolicyPageProps extends TelemetryProps, T
authenticatedUser: AuthenticatedUser | null
indexingEnabled?: boolean
allowGlobalPolicies?: boolean
domain?: 'scip' | 'embeddings'
}
type PolicyUpdater = <K extends keyof CodeIntelligenceConfigurationPolicyFields>(updates: {
@ -75,7 +74,6 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
authenticatedUser,
indexingEnabled = window.context?.codeIntelAutoIndexingEnabled,
allowGlobalPolicies = window.context?.codeIntelAutoIndexingAllowGlobalPolicies,
domain = 'scip',
telemetryService,
telemetryRecorder,
}) => {
@ -85,8 +83,8 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
useEffect(() => {
telemetryService.logViewEvent('CodeIntelConfigurationPolicy')
telemetryRecorder.recordEvent(getViewEventFeatureName(domain, !!repo), 'view')
}, [telemetryService, telemetryRecorder, domain, repo])
telemetryRecorder.recordEvent(getViewEventFeatureName(!!repo), 'view')
}, [telemetryService, telemetryRecorder, repo])
// Handle local policy state
const [policy, setPolicy] = useState<CodeIntelligenceConfigurationPolicyFields | undefined>()
@ -159,9 +157,7 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
useEffect(() => {
const urlType = new URLSearchParams(location.search).get('type')
const defaultTypes =
domain === 'embeddings'
? { type: GitObjectType.GIT_COMMIT, embeddingsEnabled: true }
: urlType === 'branch'
urlType === 'branch'
? { type: GitObjectType.GIT_TREE, pattern: '*' }
: urlType === 'tag'
? { type: GitObjectType.GIT_TAG, pattern: '*' }
@ -173,7 +169,7 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
setPolicy(configWithDefaults)
setSaved(configWithDefaults)
}, [policyConfig, repo, domain, location.search])
}, [policyConfig, repo, location.search])
if (loadingPolicyConfig) {
return <LoadingSpinner />
@ -188,8 +184,8 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
<PageTitle
title={
repo
? (domain === 'scip' ? 'Code graph' : 'Embeddings') + ' configuration policy for repository'
: `Global ${domain === 'scip' ? 'code graph data' : 'embeddings'} configuration policy`
? 'Code graph configuration policy for repository'
: 'Global code graph data configuration policy'
}
/>
<PageHeader
@ -198,32 +194,25 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
{
text: repo ? (
<>
{policy?.id === '' ? 'Create a new' : 'Update a'}{' '}
{domain === 'scip' ? 'code graph' : 'embeddings'} configuration policy for{' '}
{policy?.id === '' ? 'Create a new' : 'Update a'} code graph configuration policy for{' '}
<RepoLink repoName={repo.name} to={null} />
</>
) : (
<>
{policy?.id === '' ? 'Create a new' : 'Update a'} global{' '}
{domain === 'scip' ? 'code graph' : 'embeddings'} configuration policy
{policy?.id === '' ? 'Create a new' : 'Update a'} global code graph configuration policy
</>
),
},
]}
description={
domain === 'scip' ? (
<>
Rules that control{indexingEnabled && <> auto-indexing and</>} data retention behavior of
code graph data.
</>
) : (
<>Rules that control keeping embeddings up-to-date.</>
)
<>
Rules that control{indexingEnabled && <> auto-indexing and</>} data retention behavior of code
graph data.
</>
}
className="mb-3"
/>
{!policy.id && authenticatedUser?.siteAdmin && <NavigationCTA repo={repo} domain={domain} />}
{!policy.id && authenticatedUser?.siteAdmin && <NavigationCTA repo={repo} />}={true}{' '}
{savingError && <ErrorAlert prefix="Error saving configuration policy" error={savingError} />}
{deleteError && <ErrorAlert prefix="Error deleting configuration policy" error={deleteError} />}
{location.state && <FlashMessage state={location.state.modal} message={location.state.message} />}
@ -233,21 +222,13 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
the retention duration and indexing options are editable.
</Alert>
)}
<Container className="container form">
<NameSettingsSection policy={policy} updatePolicy={updatePolicy} domain={domain} repo={repo} />
{domain === 'scip' && <GitConfiguration policy={policy} updatePolicy={updatePolicy} repo={repo} />}
<NameSettingsSection policy={policy} updatePolicy={updatePolicy} repo={repo} />
<GitConfiguration policy={policy} updatePolicy={updatePolicy} repo={repo} />
{!policy.repository && <RepositorySettingsSection policy={policy} updatePolicy={updatePolicy} />}
{domain === 'scip' ? (
<>
{indexingEnabled && (
<IndexSettingsSection policy={policy} updatePolicy={updatePolicy} repo={repo} />
)}
<RetentionSettingsSection policy={policy} updatePolicy={updatePolicy} />
</>
) : (
<EmbeddingsSettingsSection policy={policy} updatePolicy={updatePolicy} />
)}
{indexingEnabled && <IndexSettingsSection policy={policy} updatePolicy={updatePolicy} repo={repo} />}
<RetentionSettingsSection policy={policy} updatePolicy={updatePolicy} />
<div className="mt-4">
<Button
@ -326,36 +307,31 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
interface NavigationCTAProps {
repo?: { id: string; name: string }
domain?: 'scip' | 'embeddings'
}
const NavigationCTA: FunctionComponent<NavigationCTAProps> = ({ repo, domain = 'scip' }) => (
const NavigationCTA: FunctionComponent<NavigationCTAProps> = ({ repo }) => (
<Container className="mb-2">
{repo ? (
<>
Alternatively,{' '}
<Link to={`/site-admin/${domain === 'scip' ? 'code-graph' : 'embeddings'}/configuration/new`}>
create global configuration policy
</Link>{' '}
that applies to more than this repository.
<Link to="/site-admin/code-graph/configuration/new">create global configuration policy</Link> that
applies to more than this repository.
</>
) : (
<>
To create a policy that applies to a particular repository, visit that repository's{' '}
{domain === 'scip' ? 'code graph' : 'embeddings'} settings.
To create a policy that applies to a particular repository, visit that repository's code graph settings.
</>
)}
</Container>
)
interface NameSettingsSectionProps {
domain: 'scip' | 'embeddings'
policy: CodeIntelligenceConfigurationPolicyFields
updatePolicy: PolicyUpdater
repo?: { id: string; name: string }
}
const NameSettingsSection: FunctionComponent<NameSettingsSectionProps> = ({ domain, repo, policy, updatePolicy }) => (
const NameSettingsSection: FunctionComponent<NameSettingsSectionProps> = ({ repo, policy, updatePolicy }) => (
<div className="form-group">
<div className="input-group">
<Input
@ -368,15 +344,7 @@ const NameSettingsSection: FunctionComponent<NameSettingsSectionProps> = ({ doma
required={true}
error={policy.name === '' ? 'Please supply a value' : undefined}
placeholder={`Custom ${!repo ? 'global ' : ''}${
domain === 'scip'
? policy.indexingEnabled
? 'indexing '
: policy.retentionEnabled
? 'retention '
: ''
: policy.embeddingsEnabled
? 'embeddings '
: ''
policy.indexingEnabled ? 'indexing ' : policy.retentionEnabled ? 'retention ' : ''
}policy${repo ? ` for ${displayRepoName(repo.name)}` : ''}`}
/>
</div>
@ -898,24 +866,6 @@ const RetentionSettings: FunctionComponent<RetentionSettingsProps> = ({ policy,
</>
)
interface EmbeddingsSettingsSectionProps {
policy: CodeIntelligenceConfigurationPolicyFields
updatePolicy: PolicyUpdater
}
const EmbeddingsSettingsSection: FunctionComponent<EmbeddingsSettingsSectionProps> = ({ policy, updatePolicy }) => (
<div className="form-group">
<Label className="mb-0">
<Icon aria-hidden={true} svgPath={mdiCheck} /> Keep embeddings up-to-date
<div className={styles.toggleContainer}>
<Text size="small" className="text-muted mb-0">
This policy will ensure that embeddings will be maintained for the matching repositories.
</Text>
</div>
</Label>
</div>
)
function validatePolicy(
policy: CodeIntelligenceConfigurationPolicyFields,
globalAutoIndexingEnabled: boolean
@ -986,16 +936,8 @@ function comparePatterns(a: string[] | null, b: string[] | null): boolean {
return a.length === b.length && a.every((pattern, index) => b[index] === pattern)
}
type viewEventFeatureName =
| 'repo.codeIntel.configurationPolicy'
| 'admin.codeIntel.configurationPolicy'
| 'repo.cody.configurationPolicy'
| 'admin.cody.configurationPolicy'
type viewEventFeatureName = 'repo.codeIntel.configurationPolicy' | 'admin.codeIntel.configurationPolicy'
function getViewEventFeatureName(domain: string, hasRepo: boolean): viewEventFeatureName {
if (domain === 'scip') {
return hasRepo ? 'repo.codeIntel.configurationPolicy' : 'admin.codeIntel.configurationPolicy'
}
return hasRepo ? 'repo.cody.configurationPolicy' : 'admin.cody.configurationPolicy'
function getViewEventFeatureName(hasRepo: boolean): viewEventFeatureName {
return hasRepo ? 'repo.codeIntel.configurationPolicy' : 'admin.codeIntel.configurationPolicy'
}

View File

@ -1,14 +0,0 @@
import React from 'react'
import { mdiMapSearch } from '@mdi/js'
import { H4, Icon } from '@sourcegraph/wildcard'
interface EmptyPoliciesListProps {}
export const EmptyPoliciesList: React.FunctionComponent<EmptyPoliciesListProps> = () => (
<div className="d-flex align-items-center flex-column w-100 mt-3" data-testid="summary">
<Icon className="mb-2" svgPath={mdiMapSearch} inline={false} aria-hidden={true} />
<H4 className="mb-0">No embeddings policies found.</H4>
</div>
)

View File

@ -1,159 +0,0 @@
import { type FC, useCallback, useEffect, useMemo } from 'react'
import { useApolloClient } from '@apollo/client'
import classNames from 'classnames'
import { useLocation, useNavigate } from 'react-router-dom'
import { Subject } from 'rxjs'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { RepoLink } from '@sourcegraph/shared/src/components/RepoLink'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { Button, Container, ErrorAlert, Link, PageHeader } from '@sourcegraph/wildcard'
import { CodyColorIcon } from '../../../../cody/chat/CodyPageIcon'
import { FilteredConnection, type FilteredConnectionQueryArguments } from '../../../../components/FilteredConnection'
import { PageTitle } from '../../../../components/PageTitle'
import type { CodeIntelligenceConfigurationPolicyFields } from '../../../../graphql-operations'
import { FlashMessage } from '../../../codeintel/configuration/components/FlashMessage'
import { queryPolicies as defaultQueryPolicies } from '../../../codeintel/configuration/hooks/queryPolicies'
import { useDeletePolicies } from '../../../codeintel/configuration/hooks/useDeletePolicies'
import {
PoliciesNode,
type UnprotectedPoliciesNodeProps,
} from '../../../codeintel/configuration/pages/CodeIntelConfigurationPage'
import { EmptyPoliciesList } from '../components/EmptyPoliciesList'
import styles from '../../../codeintel/configuration/pages/CodeIntelConfigurationPage.module.scss'
export interface CodyConfigurationPageProps extends TelemetryProps, TelemetryV2Props {
authenticatedUser: AuthenticatedUser | null
queryPolicies?: typeof defaultQueryPolicies
repo?: { id: string; name: string }
}
/* eslint-disable @sourcegraph/sourcegraph/check-help-links */
export const CodyConfigurationPage: FC<CodyConfigurationPageProps> = ({
authenticatedUser,
queryPolicies = defaultQueryPolicies,
repo,
telemetryService,
telemetryRecorder,
}) => {
useEffect(() => {
telemetryService.logPageView('CodyConfigurationPage')
if (repo) {
telemetryRecorder.recordEvent('repo.cody.configuration', 'view')
} else {
telemetryRecorder.recordEvent('admin.cody.configuration', 'view')
}
}, [telemetryService, telemetryRecorder, repo])
const navigate = useNavigate()
const location = useLocation()
const updates = useMemo(() => new Subject<void>(), [])
const apolloClient = useApolloClient()
const queryPoliciesCallback = useCallback(
(args: FilteredConnectionQueryArguments) =>
queryPolicies({ ...args, repository: repo?.id, forEmbeddings: true }, apolloClient),
[queryPolicies, repo?.id, apolloClient]
)
const { handleDeleteConfig, isDeleting, deleteError } = useDeletePolicies()
const onDelete = useCallback(
async (id: string, name: string) => {
if (!window.confirm(`Delete policy ${name}?`)) {
return
}
return handleDeleteConfig({
variables: { id },
}).then(() => {
// Force update of filtered connection
updates.next()
navigate(
{
pathname: './',
},
{
relative: 'path',
state: { modal: 'SUCCESS', message: `Configuration policy ${name} has been deleted.` },
}
)
})
},
[handleDeleteConfig, updates, navigate]
)
return (
<>
<PageTitle title={repo ? 'Embeddings policies for repository' : 'Global embeddings policies'} />
<PageHeader
headingElement="h2"
path={[
{ icon: CodyColorIcon, text: 'Cody' },
{
text: repo ? (
<>
Embeddings policies for <RepoLink repoName={repo.name} to={null} />
</>
) : (
'Global embeddings policies'
),
},
]}
description={
<>
Rules that control keeping embeddings up-to-date. See the{' '}
<Link target="_blank" to="/help/cody/explanations/policies">
documentation
</Link>{' '}
for more details.
</>
}
actions={
authenticatedUser?.siteAdmin && (
<Button to="./new?type=head" variant="primary" as={Link}>
Create new {!repo && 'global'} policy
</Button>
)
}
className="mb-3"
/>
{deleteError && <ErrorAlert prefix="Error deleting configuration policy" error={deleteError} />}
{location.state && <FlashMessage state={location.state.modal} message={location.state.message} />}
{authenticatedUser?.siteAdmin && repo && (
<Container className="mb-2">
View <Link to="/site-admin/embeddings/configuration">additional configuration policies</Link> that
do not affect this repository.
</Container>
)}
<Container className="mb-3 pb-3">
<FilteredConnection<
CodeIntelligenceConfigurationPolicyFields,
Omit<UnprotectedPoliciesNodeProps, 'node'>
>
listComponent="div"
listClassName={classNames(styles.grid, 'mb-3')}
showMoreClassName="mb-0"
noun="configuration policy"
pluralNoun="configuration policies"
nodeComponent={PoliciesNode}
nodeComponentProps={{ isDeleting, onDelete, domain: 'embeddings' }}
queryConnection={queryPoliciesCallback}
cursorPaging={true}
inputClassName="ml-2 flex-1"
emptyElement={<EmptyPoliciesList />}
updates={updates}
/>
</Container>
</>
)
}

View File

@ -1,95 +0,0 @@
import type { FC } from 'react'
import { Navigate, Route, Routes } from 'react-router-dom'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
import type { AuthenticatedUser } from '../../../auth'
import type { BreadcrumbSetters } from '../../../components/Breadcrumbs'
import { NotFoundPage } from '../../../components/HeroPage'
import type { RepositoryFields } from '../../../graphql-operations'
import type { RouteV6Descriptor } from '../../../util/contributions'
import type { CodeIntelConfigurationPolicyPageProps } from '../../codeintel/configuration/pages/CodeIntelConfigurationPolicyPage'
import { CodyConfigurationPage } from '../configuration/pages/CodyConfigurationPage'
import { CodyRepoSidebar, type CodyRepoSidebarGroups } from './CodyRepoSidebar'
export interface CodyRepoAreaRouteContext extends TelemetryProps, TelemetryV2Props {
repo: { id: string; name: string }
authenticatedUser: AuthenticatedUser | null
}
export interface CodyRepoAreaRoute extends RouteV6Descriptor<CodyRepoAreaRouteContext> {}
const CodeIntelConfigurationPolicyPage = lazyComponent<
CodeIntelConfigurationPolicyPageProps,
'CodeIntelConfigurationPolicyPage'
>(
() => import('../../codeintel/configuration/pages/CodeIntelConfigurationPolicyPage'),
'CodeIntelConfigurationPolicyPage'
)
export const codyRepoAreaRoutes: readonly CodyRepoAreaRoute[] = [
{
path: '/',
render: () => <Navigate to="./configuration" replace={true} />,
},
{
path: '/configuration',
render: props => <CodyConfigurationPage {...props} />,
},
{
path: '/configuration/:id',
render: props => <CodeIntelConfigurationPolicyPage {...props} domain="embeddings" />,
},
]
export interface CodyRepoAreaProps extends BreadcrumbSetters, TelemetryProps, TelemetryV2Props {
repo: RepositoryFields
authenticatedUser: AuthenticatedUser | null
}
const sidebarRoutes: CodyRepoSidebarGroups = [
{
header: { label: 'Embeddings' },
items: [
{
to: '/configuration',
label: 'Configuration policies',
},
],
},
]
const BREADCRUMB = { key: 'embeddings', element: 'Embeddings' }
export const CodyRepoArea: FC<CodyRepoAreaProps> = props => {
const { useBreadcrumb, repo } = props
useBreadcrumb(BREADCRUMB)
return (
<div className="container d-flex mt-3">
<CodyRepoSidebar className="flex-0 mr-3" codyRepoSidebarGroups={sidebarRoutes} repo={repo} />
<div className="flex-bounded">
<Routes>
{codyRepoAreaRoutes.map(
({ path, render, condition = () => true }) =>
condition(props) && (
<Route
key="hardcoded-key" // see https://github.com/ReactTraining/react-router/issues/4578#issuecomment-334489490
path={path}
element={render(props)}
/>
)
)}
<Route path="*" element={<NotFoundPage pageType="repository" />} />
</Routes>
</div>
</div>
)
}

View File

@ -1,29 +0,0 @@
import type { FC } from 'react'
import { SidebarGroupHeader, SidebarGroup, SidebarNavItem } from '../../../components/Sidebar'
import type { NavGroupDescriptor } from '../../../util/contributions'
export interface CodyRepoSideBarGroup extends NavGroupDescriptor {}
export type CodyRepoSidebarGroups = readonly CodyRepoSideBarGroup[]
interface Props {
codyRepoSidebarGroups: CodyRepoSidebarGroups
className?: string
repo: { url: string }
}
export const CodyRepoSidebar: FC<Props> = ({ codyRepoSidebarGroups, className, repo }) => (
<div className={className}>
{codyRepoSidebarGroups.map(({ header, items }, index) => (
<SidebarGroup key={index}>
{header && <SidebarGroupHeader label={header.label} />}
{items.map(({ label, to }) => (
<SidebarNavItem to={`${repo.url}/-/embeddings${to}`} key={label}>
{label}
</SidebarNavItem>
))}
</SidebarGroup>
))}
</div>
)

View File

@ -9,8 +9,6 @@ const RepositoryCodeIntelArea = lazyComponent(
'RepositoryCodeIntelArea'
)
const CodyRepoArea = lazyComponent(() => import('../cody/repo/CodyRepoArea'), 'CodyRepoArea')
const RepositoryBatchChangesArea = lazyComponent(
() => import('../batches/repo/RepositoryBatchChangesArea'),
'RepositoryBatchChangesArea'
@ -36,10 +34,6 @@ export const enterpriseRepoContainerRoutes: readonly RepoContainerRoute[] = [
<RepositoryCodeIntelArea {...context} telemetryRecorder={context.platformContext.telemetryRecorder} />
),
},
{
path: '/-/embeddings/*',
render: context => <CodyRepoArea {...context} telemetryRecorder={context.platformContext.telemetryRecorder} />,
},
{
path: '/-/batch-changes',
condition: ({ batchChangesEnabled }) => batchChangesEnabled,

View File

@ -1,12 +0,0 @@
.badge-wrapper {
min-width: 90px;
}
.error-content {
max-width: 600px;
}
.alert-overflow {
max-height: 300px;
overflow-y: auto;
}

View File

@ -1,215 +0,0 @@
import { type FC, useState, useEffect } from 'react'
import classNames from 'classnames'
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
import {
Badge,
Button,
PopoverTrigger,
PopoverContent,
PopoverTail,
Popover,
Position,
type BadgeVariantType,
Link,
H4,
Alert,
Tooltip,
} from '@sourcegraph/wildcard'
import { type RepoEmbeddingJobFields, RepoEmbeddingJobState } from '../../../graphql-operations'
import styles from './RepoEmbeddingJobNode.module.scss'
interface RepoEmbeddingJobNodeProps extends RepoEmbeddingJobFields {
onCancel: (id: string) => void
}
export const RepoEmbeddingJobNode: FC<RepoEmbeddingJobNodeProps> = ({
id,
state,
cancel,
repo,
revision,
finishedAt,
queuedAt,
startedAt,
failureMessage,
stats,
onCancel,
}) => (
<li className="list-group-item p-2">
<div className="d-flex justify-content-between">
<div className="d-flex align-items-center">
<div className={styles.badgeWrapper}>
<RepoEmbeddingJobStateBadge state={state} />
</div>
<div className="d-flex flex-column ml-3">
{repo && revision ? (
<Link to={`${repo.url}@${revision.oid}`}>
{repo.name}@{revision.abbreviatedOID}
</Link>
) : repo ? (
<>{repo.name}</>
) : (
<div>Unknown repository</div>
)}
<div className="mt-1">
<RepoEmbeddingJobExecutionInfo
state={state}
cancel={cancel}
finishedAt={finishedAt}
queuedAt={queuedAt}
startedAt={startedAt}
failureMessage={failureMessage}
stats={stats}
/>
</div>
</div>
</div>
<div className="d-flex align-items-center">
{state === RepoEmbeddingJobState.QUEUED || state === RepoEmbeddingJobState.PROCESSING ? (
<Tooltip content="Cancel repository embedding job">
<Button
aria-label="Cancel"
onClick={() => onCancel(id)}
variant="secondary"
size="sm"
disabled={cancel}
>
Cancel
</Button>
</Tooltip>
) : null}
</div>
</div>
</li>
)
const RepoEmbeddingJobExecutionInfo: FC<
Pick<
RepoEmbeddingJobFields,
'state' | 'cancel' | 'finishedAt' | 'failureMessage' | 'queuedAt' | 'startedAt' | 'stats'
>
> = ({ state, cancel, finishedAt, queuedAt, startedAt, failureMessage, stats }) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
const [estimatedFinish, setEstimatedFinish] = useState<Date | null>(null)
useEffect(() => {
setEstimatedFinish(
calculateEstimatedFinish(startedAt, stats.filesScheduled, stats.filesEmbedded, stats.filesSkipped)
)
}, [startedAt, stats.filesScheduled, stats.filesEmbedded, stats.filesSkipped])
return (
<>
{state === RepoEmbeddingJobState.COMPLETED && finishedAt && (
<small>
Completed embedding {stats.filesEmbedded} files ({stats.filesSkipped} skipped){' '}
<Timestamp date={finishedAt} />
</small>
)}
{state === RepoEmbeddingJobState.CANCELED && finishedAt && (
<small>
Stopped <Timestamp date={finishedAt} />
</small>
)}
{state === RepoEmbeddingJobState.QUEUED && (
<small>
{cancel ? (
'Cancelling ...'
) : (
<>
Queued <Timestamp date={queuedAt} />
</>
)}
</small>
)}
{state === RepoEmbeddingJobState.PROCESSING && startedAt && (
<small>
{cancel ? (
'Cancelling ...'
) : estimatedFinish ? (
<>
Expected to finish <Timestamp date={estimatedFinish} /> (
{stats.filesSkipped + stats.filesEmbedded}/{stats.filesScheduled} files)
</>
) : (
<>
Started processing <Timestamp date={startedAt} />
</>
)}
</small>
)}
{(state === RepoEmbeddingJobState.ERRORED || state === RepoEmbeddingJobState.FAILED) && failureMessage && (
<Popover isOpen={isPopoverOpen} onOpenChange={event => setIsPopoverOpen(event.isOpen)}>
<PopoverTrigger as={Button} variant="secondary" size="sm" aria-label="See errors">
See errors
</PopoverTrigger>
<PopoverContent position={Position.right} className={styles.errorContent}>
<Alert variant="danger" className={classNames('m-2', styles.alertOverflow)}>
<H4>Error embedding repository:</H4>
<div>{failureMessage}</div>
</Alert>
</PopoverContent>
<PopoverTail size="sm" />
</Popover>
)}
</>
)
}
function calculateEstimatedFinish(
startedAt: string | null,
filesScheduled: number,
filesEmbedded: number,
filesSkipped: number,
now?: number
): Date | null {
const currentTime = now ?? Date.now()
if (!startedAt) {
return null
}
const startTime = Date.parse(startedAt)
if (filesScheduled === 0) {
// There is a period between when the job starts processing and when
// we know how many files need to be processed. In the case where
// we do not have an update with the number of files scheduled,
// we cannot calculate a meaningful ETA.
return null
}
const proportionFinished = (filesEmbedded + filesSkipped) / filesScheduled
const timeElapsed = currentTime - startTime
const estimatedTotalTime = timeElapsed / proportionFinished
return new Date(startTime + estimatedTotalTime)
}
function getRepoEmbeddingJobStateBadgeVariant(state: RepoEmbeddingJobState): BadgeVariantType {
switch (state) {
case RepoEmbeddingJobState.COMPLETED: {
return 'success'
}
case RepoEmbeddingJobState.CANCELED: {
return 'warning'
}
case RepoEmbeddingJobState.ERRORED:
case RepoEmbeddingJobState.FAILED: {
return 'danger'
}
case RepoEmbeddingJobState.QUEUED:
case RepoEmbeddingJobState.PROCESSING: {
return 'info'
}
}
}
const RepoEmbeddingJobStateBadge: React.FunctionComponent<{ state: RepoEmbeddingJobState }> = ({ state }) => (
<Badge
variant={getRepoEmbeddingJobStateBadgeVariant(state)}
className={classNames('py-0 px-1 text-uppercase font-weight-normal')}
>
{state}
</Badge>
)

View File

@ -1,3 +0,0 @@
.schedule-button {
height: 2.375rem;
}

View File

@ -1,265 +0,0 @@
import { type FC, useCallback, useEffect, useState, useMemo } from 'react'
import { mdiMapSearch } from '@mdi/js'
import { capitalize } from 'lodash'
import { useLocation } from 'react-router-dom'
import { RepoEmbeddingJobState } from '@sourcegraph/shared/src/graphql-operations'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import {
Button,
Container,
getDefaultInputProps,
Label,
PageHeader,
useField,
useForm,
H3,
type Validator,
ErrorAlert,
Form,
useDebounce,
Icon,
} from '@sourcegraph/wildcard'
import { CodyColorIcon } from '../../../cody/chat/CodyPageIcon'
import type { FilteredConnectionFilter, FilteredConnectionFilterValue } from '../../../components/FilteredConnection'
import {
ConnectionContainer,
ConnectionError,
ConnectionForm,
ConnectionList,
ConnectionLoading,
ConnectionSummary,
ShowMoreButton,
SummaryContainer,
} from '../../../components/FilteredConnection/ui'
import { getFilterFromURL } from '../../../components/FilteredConnection/utils'
import { PageTitle } from '../../../components/PageTitle'
import { RepositoriesField } from '../../insights/components'
import { useCancelRepoEmbeddingJob, useRepoEmbeddingJobsConnection, useScheduleRepoEmbeddingJobs } from './backend'
import { RepoEmbeddingJobNode } from './RepoEmbeddingJobNode'
import styles from './SiteAdminCodyPage.module.scss'
export interface SiteAdminCodyPageProps extends TelemetryProps, TelemetryV2Props {}
interface RepoEmbeddingJobsFormValues {
repositories: string[]
}
const INITIAL_REPOSITORIES = { repositories: [] }
const repositoriesValidator: Validator<string[]> = value => {
if (value !== undefined && value.length === 0) {
return 'Repositories is a required field.'
}
return
}
// Helper function to convert an enum to a list of FilteredConnectionFilterValue
const enumToFilterValues = <T extends string>(enumeration: { [key in T]: T }): FilteredConnectionFilterValue[] => {
const values: FilteredConnectionFilterValue[] = []
for (const key of Object.keys(enumeration)) {
values.push({
value: key.toLowerCase(),
label: capitalize(key),
args: {},
tooltip: `Show ${key.toLowerCase()} jobs`,
})
}
return values
}
export const SiteAdminCodyPage: FC<SiteAdminCodyPageProps> = ({ telemetryService, telemetryRecorder }) => {
useEffect(() => {
telemetryService.logPageView('SiteAdminCodyPage')
telemetryRecorder.recordEvent('admin.cody.embeddingsJobs', 'view')
}, [telemetryService, telemetryRecorder])
const location = useLocation()
const searchParams = useMemo(() => new URLSearchParams(location.search), [location.search])
const queryParam = searchParams.get('query')
const [searchValue, setSearchValue] = useState(queryParam || '')
const query = useDebounce(searchValue, 200)
const defaultStateFilterValue = 'all'
const filters: FilteredConnectionFilter[] = [
{
id: 'state',
label: 'State',
type: 'select',
values: [
{
label: 'All',
value: defaultStateFilterValue,
tooltip: 'Show all jobs',
args: {},
},
...enumToFilterValues(RepoEmbeddingJobState),
],
},
]
const [filterValues, setFilterValues] = useState<Map<string, FilteredConnectionFilterValue>>(() =>
getFilterFromURL(searchParams, filters)
)
const getStateFilterValue = (filterValues: Map<string, FilteredConnectionFilterValue>): string | null => {
const val = filterValues.get('state')?.value || defaultStateFilterValue
return val === defaultStateFilterValue ? null : val
}
const { loading, hasNextPage, fetchMore, refetchAll, refetchFirst, connection, error } =
useRepoEmbeddingJobsConnection(query, getStateFilterValue(filterValues))
const [scheduleRepoEmbeddingJobs, { loading: repoEmbeddingJobsLoading, error: repoEmbeddingJobsError }] =
useScheduleRepoEmbeddingJobs()
const onSubmit = useCallback(
async (repoNames: string[]) => {
telemetryRecorder.recordEvent('admin.cody.embeddingsJobs', 'scheduleJob')
await scheduleRepoEmbeddingJobs({ variables: { repoNames } })
refetchFirst()
},
[refetchFirst, scheduleRepoEmbeddingJobs, telemetryRecorder]
)
const form = useForm<RepoEmbeddingJobsFormValues>({
initialValues: INITIAL_REPOSITORIES,
touched: false,
onSubmit: values => onSubmit(values.repositories),
})
const repositories = useField({
name: 'repositories',
formApi: form.formAPI,
validators: { sync: repositoriesValidator },
})
const updateQueryParams = (key: string, value: string): void => {
if (value === '') {
searchParams.delete(key)
} else {
searchParams.set(key, value)
}
const queryString = searchParams.toString()
const newUrl = queryString === '' ? window.location.pathname : `${window.location.pathname}?${queryString}`
window.history.replaceState(null, '', newUrl)
}
const [cancelRepoEmbeddingJob, { error: cancelRepoEmbeddingJobError }] = useCancelRepoEmbeddingJob()
const onCancel = useCallback(
async (id: string) => {
await cancelRepoEmbeddingJob({ variables: { id } })
refetchAll()
},
[cancelRepoEmbeddingJob, refetchAll]
)
return (
<>
<PageTitle title="Embeddings jobs" />
<PageHeader
path={[{ icon: CodyColorIcon, text: 'Cody' }, { text: 'Embeddings jobs' }]}
className="mb-3"
headingElement="h2"
/>
<Container className="mb-3">
<H3>Schedule repositories for embedding</H3>
<Form ref={form.ref} noValidate={true} onSubmit={form.handleSubmit}>
<Label htmlFor="repositories-id" className="mt-1">
Repositories
</Label>
<div className="d-flex">
<RepositoriesField
id="repositories-id"
description="Schedule repositories for embedding at latest revision on the default branch."
placeholder="Add repositories to schedule..."
className="flex-1 mr-2"
{...getDefaultInputProps(repositories)}
/>
<div>
<Button
type="submit"
variant="secondary"
className={styles.scheduleButton}
disabled={repoEmbeddingJobsLoading}
>
{repoEmbeddingJobsLoading ? 'Scheduling...' : 'Schedule Embedding'}
</Button>
</div>
</div>
</Form>
{(repoEmbeddingJobsError || cancelRepoEmbeddingJobError) && (
<div className="mt-1">
<ErrorAlert
prefix="Error scheduling embeddings jobs"
error={repoEmbeddingJobsError || cancelRepoEmbeddingJobError}
/>
</div>
)}
</Container>
<Container>
<H3 className="mt-3">Repository embeddings jobs</H3>
<ConnectionContainer>
<ConnectionForm
formClassName="mb-2"
inputClassName="flex-1 ml-2"
inputValue={searchValue}
onInputChange={event => {
setSearchValue(event.target.value)
updateQueryParams('query', event.target.value)
}}
inputPlaceholder="Filter embeddings jobs..."
filters={filters}
filterValues={filterValues}
onFilterSelect={(filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue) => {
setFilterValues(values => {
const newValues = new Map(values)
newValues.set(filter.id, value)
return newValues
})
updateQueryParams(filter.id, value.value)
}}
/>
{error && <ConnectionError errors={[error.message]} />}
{loading && !connection && <ConnectionLoading />}
<ConnectionList as="ul" className="list-group" aria-label="Repository embeddings jobs">
{connection?.nodes?.map(node => (
<RepoEmbeddingJobNode key={node.id} {...node} onCancel={onCancel} />
))}
</ConnectionList>
{connection && (
<SummaryContainer className="mt-2" centered={true}>
<ConnectionSummary
noSummaryIfAllNodesVisible={false}
first={connection.totalCount ?? 0}
centered={true}
connection={connection}
connectionQuery={query}
noun="repository embeddings job"
pluralNoun="repository embeddings jobs"
hasNextPage={hasNextPage}
emptyElement={<EmptyList />}
/>
{hasNextPage && <ShowMoreButton centered={true} onClick={fetchMore} />}
</SummaryContainer>
)}
</ConnectionContainer>
</Container>
</>
)
}
const EmptyList: FC<{}> = () => (
<div className="text-muted text-center mb-3 w-100">
<Icon className="mb-2" svgPath={mdiMapSearch} inline={false} aria-hidden={true} />
<div className="pt-2">No repository embeddings jobs found.</div>
</div>
)

View File

@ -1,107 +0,0 @@
import type { MutationTuple } from '@apollo/client'
import { dataOrThrowErrors, gql, useMutation } from '@sourcegraph/http-client'
import {
useShowMorePagination,
type UseShowMorePaginationResult,
} from '../../../components/FilteredConnection/hooks/useShowMorePagination'
import type {
CancelRepoEmbeddingJobResult,
CancelRepoEmbeddingJobVariables,
RepoEmbeddingJobFields,
RepoEmbeddingJobsListResult,
RepoEmbeddingJobsListVariables,
ScheduleRepoEmbeddingJobsResult,
ScheduleRepoEmbeddingJobsVariables,
} from '../../../graphql-operations'
const REPO_EMBEDDING_JOB_FRAGMENT = gql`
fragment RepoEmbeddingJobFields on RepoEmbeddingJob {
id
state
failureMessage
finishedAt
queuedAt
startedAt
cancel
repo {
name
url
}
revision {
oid
abbreviatedOID
}
stats {
filesScheduled
filesEmbedded
filesSkipped
}
}
`
export const REPO_EMBEDDING_JOBS_LIST_QUERY = gql`
${REPO_EMBEDDING_JOB_FRAGMENT}
query RepoEmbeddingJobsList($first: Int, $after: String, $query: String, $state: String) {
repoEmbeddingJobs(first: $first, after: $after, query: $query, state: $state) {
nodes {
...RepoEmbeddingJobFields
}
totalCount
pageInfo {
endCursor
hasNextPage
}
}
}
`
export const useRepoEmbeddingJobsConnection = (
query: string,
state: string | null
): UseShowMorePaginationResult<RepoEmbeddingJobsListResult, RepoEmbeddingJobFields> =>
useShowMorePagination<RepoEmbeddingJobsListResult, RepoEmbeddingJobsListVariables, RepoEmbeddingJobFields>({
query: REPO_EMBEDDING_JOBS_LIST_QUERY,
variables: { after: null, first: 10, query, state },
getConnection: result => {
const { repoEmbeddingJobs } = dataOrThrowErrors(result)
return repoEmbeddingJobs
},
options: {
pollInterval: 5000,
},
})
export const SCHEDULE_REPO_EMBEDDING_JOBS = gql`
mutation ScheduleRepoEmbeddingJobs($repoNames: [String!]!) {
scheduleRepositoriesForEmbedding(repoNames: $repoNames) {
alwaysNil
}
}
`
export function useScheduleRepoEmbeddingJobs(): MutationTuple<
ScheduleRepoEmbeddingJobsResult,
ScheduleRepoEmbeddingJobsVariables
> {
return useMutation<ScheduleRepoEmbeddingJobsResult, ScheduleRepoEmbeddingJobsVariables>(
SCHEDULE_REPO_EMBEDDING_JOBS
)
}
export const CANCEL_REPO_EMBEDDING_JOB = gql`
mutation CancelRepoEmbeddingJob($id: ID!) {
cancelRepoEmbeddingJob(job: $id) {
alwaysNil
}
}
`
export function useCancelRepoEmbeddingJob(): MutationTuple<
CancelRepoEmbeddingJobResult,
CancelRepoEmbeddingJobVariables
> {
return useMutation<CancelRepoEmbeddingJobResult, CancelRepoEmbeddingJobVariables>(CANCEL_REPO_EMBEDDING_JOB)
}

View File

@ -76,7 +76,6 @@ export const createJsContext = ({ sourcegraphBaseUrl }: { sourcegraphBaseUrl: st
xhrHeaders: {},
authProviders: [builtinAuthProvider],
authMinPasswordLength: 12,
embeddingsEnabled: false,
runningOnMacOS: true,
primaryLoginProvidersCount: 5,
// use noOpTelemetryRecorder since this jsContext is only used for integration tests.

View File

@ -239,9 +239,6 @@ export interface SourcegraphContext extends Pick<Required<SiteConfiguration>, 'e
/** Whether the own API is enabled on the Sourcegraph instance */
ownEnabled: boolean
/** Whether embeddings are enabled on this site. */
embeddingsEnabled: boolean
/** Authentication provider instances in site config. */
authProviders: AuthProvider[]

View File

@ -1,10 +0,0 @@
import { gql } from '@sourcegraph/http-client'
export const REPO_EMBEDDING_EXISTS_QUERY = gql`
query RepoEmbeddingExistsQuery($repoName: String!) {
repository(name: $repoName) {
id
embeddingExists
}
}
`

View File

@ -1,4 +1,4 @@
import React, { type FC, useEffect, useMemo } from 'react'
import React, { useEffect, useMemo, type FC } from 'react'
import {
mdiAccount,
@ -12,13 +12,12 @@ import {
mdiSourceFork,
mdiSourceRepository,
mdiTag,
mdiVectorPolyline,
} from '@mdi/js'
import classNames from 'classnames'
import { Navigate } from 'react-router-dom'
import { catchError } from 'rxjs/operators'
import { asError, encodeURIPathComponent, type ErrorLike, isErrorLike, basename } from '@sourcegraph/common'
import { asError, basename, encodeURIPathComponent, isErrorLike, type ErrorLike } from '@sourcegraph/common'
import { gql, useQuery } from '@sourcegraph/http-client'
import { fetchTreeEntries } from '@sourcegraph/shared/src/backend/repo'
import { displayRepoName } from '@sourcegraph/shared/src/components/RepoLink'
@ -26,7 +25,7 @@ import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/cont
import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import type { SearchContextProps } from '@sourcegraph/shared/src/search'
import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { toPrettyBlobURL } from '@sourcegraph/shared/src/util/url'
import {
@ -47,7 +46,7 @@ import type { AuthenticatedUser } from '../../auth'
import type { BatchChangesProps } from '../../batches'
import { RepoBatchChangesButton } from '../../batches/RepoBatchChangesButton'
import type { CodeIntelligenceProps } from '../../codeintel'
import { isCodyEnabled, isEmbeddingsEnabled } from '../../cody/isCodyEnabled'
import { isCodyEnabled } from '../../cody/isCodyEnabled'
import type { BreadcrumbSetters } from '../../components/Breadcrumbs'
import { PageTitle } from '../../components/PageTitle'
import type { FileCommitsResult, FileCommitsVariables, RepositoryFields } from '../../graphql-operations'
@ -302,20 +301,6 @@ export const TreePage: FC<Props> = ({
</Button>
</Tooltip>
)}
{isEmbeddingsEnabled() && (
<Tooltip content="Embeddings">
<Button
className="flex-shrink-0"
to={`/${encodeURIPathComponent(repoName)}/-/embeddings`}
variant="secondary"
outline={true}
as={Link}
>
<Icon aria-hidden={true} svgPath={mdiVectorPolyline} />{' '}
<span className={styles.text}>Embeddings</span>
</Button>
</Tooltip>
)}
{batchChangesEnabled && !isPackage && (
<Tooltip content="Batch changes">
<RepoBatchChangesButton

View File

@ -43,8 +43,3 @@
min-height: 16px;
min-width: 16px;
}
.embeddings {
background-color: var(--success) !important;
color: var(--white) !important;
}

View File

@ -8,11 +8,10 @@ import {
mdiDatabaseRefresh,
mdiDotsVertical,
mdiInformation,
mdiRefresh,
mdiSecurity,
mdiVectorPolyline,
mdiListStatus,
mdiRefresh,
mdiSearchWeb,
mdiSecurity,
} from '@mdi/js'
import classNames from 'classnames'
import { useNavigate } from 'react-router-dom'
@ -25,7 +24,6 @@ import {
Button,
H4,
Icon,
Link,
LinkOrSpan,
LoadingSpinner,
Menu,
@ -40,7 +38,6 @@ import {
Position,
} from '@sourcegraph/wildcard'
import { isEmbeddingsEnabled } from '../cody/isCodyEnabled'
import type {
RecloneRepositoryResult,
RecloneRepositoryVariables,
@ -120,14 +117,6 @@ export const RepositoryNode: React.FunctionComponent<React.PropsWithChildren<Rep
<div className="d-flex align-items-center col justify-content-start px-0 px-md-2 mt-2 mt-md-0">
<RepositoryStatusBadge status={parseRepositoryStatus(node)} />
{node.embeddingExists && (
<Link
className="d-flex ml-2"
to={`/site-admin/embeddings?query=${encodeURIComponent(node.name)}`}
>
<RepositoryStatusBadge status="embeddings" />
</Link>
)}
{node.mirrorInfo.cloneInProgress && <LoadingSpinner className="ml-2" />}
{node.mirrorInfo.lastError && (
<Popover isOpen={isPopoverOpen} onOpenChange={event => setIsPopoverOpen(event.isOpen)}>
@ -228,17 +217,6 @@ export const RepositoryNode: React.FunctionComponent<React.PropsWithChildren<Rep
<Icon aria-hidden={true} svgPath={mdiSearchWeb} className="mr-1" />
Search indexing
</MenuItem>
{isEmbeddingsEnabled() && (
<MenuItem
as={Button}
disabled={!repoClonedAndHealthy(node)}
onSelect={() => navigate(`/${node.name}/-/embeddings/configuration`)}
className="p-2"
>
<Icon aria-hidden={true} svgPath={mdiVectorPolyline} className="mr-1" />
Embeddings
</MenuItem>
)}
<MenuItem
as={Button}
disabled={!repoClonedAndHealthy(node)}

View File

@ -428,13 +428,6 @@ export const SiteAdminPingsPage: React.FunctionComponent<React.PropsWithChildren
<li>Completion model (included only for "sourcegraph" provider)</li>
</ul>
</li>
<li>
Embeddings
<ul>
<li>Provider (e.g., "sourcegraph", "openai", "azure-openai", etc.)</li>
<li>Model</li>
</ul>
</li>
</ul>
</li>
<li>Whether Cody context filters are configured in the site config (true/false)</li>

View File

@ -6,7 +6,6 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { useQuery } from '@sourcegraph/http-client'
import { Container, ErrorAlert, Input, LoadingSpinner, PageSwitcher, useDebounce } from '@sourcegraph/wildcard'
import { isEmbeddingsEnabled } from '../cody/isCodyEnabled'
import { EXTERNAL_SERVICE_IDS_AND_NAMES } from '../components/externalServices/backend'
import {
buildFilterArgs,
@ -17,18 +16,18 @@ import {
import { usePageSwitcherPagination } from '../components/FilteredConnection/hooks/usePageSwitcherPagination'
import { getFilterFromURL, getUrlQuery } from '../components/FilteredConnection/utils'
import {
RepositoryOrderBy,
type ExternalServiceIDsAndNamesResult,
type ExternalServiceIDsAndNamesVariables,
type RepositoriesResult,
type RepositoriesVariables,
RepositoryOrderBy,
type SiteAdminRepositoryFields,
type StatusAndRepoStatsResult,
} from '../graphql-operations'
import { PageRoutes } from '../routes.constants'
import { ValueLegendList, type ValueLegendListProps } from './analytics/components/ValueLegendList'
import { REPOSITORIES_QUERY, REPO_PAGE_POLL_INTERVAL, STATUS_AND_REPO_STATS } from './backend'
import { REPO_PAGE_POLL_INTERVAL, REPOSITORIES_QUERY, STATUS_AND_REPO_STATS } from './backend'
import { RepositoryNode } from './RepositoryNode'
import styles from './SiteAdminRepositoriesContainer.module.scss'
@ -82,12 +81,6 @@ const STATUS_FILTERS: { [label: string]: FilteredConnectionFilterValue } = {
tooltip: 'Show only repositories which are corrupt',
args: { corrupted: true },
},
Embedded: {
label: 'Embedded',
value: 'embedded',
tooltip: 'Show only repositories which are embedded',
args: { notEmbedded: false },
},
}
const FILTERS: FilteredConnectionFilter[] = [
@ -254,8 +247,6 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
query: searchQuery,
indexed: args.indexed ?? true,
notIndexed: args.notIndexed ?? true,
embedded: args.embedded ?? true,
notEmbedded: args.notEmbedded ?? true,
failedFetch: args.failedFetch ?? false,
corrupted: args.corrupted ?? false,
cloneStatus: args.cloneStatus ?? null,
@ -365,22 +356,6 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
},
]
if (isEmbeddingsEnabled()) {
items.push({
value: data.repositoryStats.embedded,
description: 'Embedded',
color: 'var(--body-color)',
position: 'right',
tooltip: 'The number of repositories that have been embedded for Cody.',
onClick: () =>
setFilterValues(values => {
const newValues = new Map(values)
newValues.set('status', STATUS_FILTERS.Embedded)
return newValues
}),
})
}
if (data.repositoryStats.corrupted > 0) {
items.push({
value: data.repositoryStats.corrupted,

View File

@ -21,6 +21,9 @@ import type {
FeatureFlagFields,
FeatureFlagsResult,
FeatureFlagsVariables,
GitserverFields,
GitserversResult,
GitserversVariables,
OrganizationsConnectionFields,
OrganizationsResult,
OrganizationsVariables,
@ -54,9 +57,6 @@ import type {
WebhookPageHeaderVariables,
WebhooksListResult,
WebhooksListVariables,
GitserversVariables,
GitserversResult,
GitserverFields,
} from '../graphql-operations'
import { accessTokenFragment } from '../settings/tokens/AccessTokenNode'
@ -149,7 +149,6 @@ const siteAdminRepositoryFieldsFragment = gql`
externalRepository {
...ExternalRepositoryFields
}
embeddingExists
}
`
export const REPOSITORIES_QUERY = gql`
@ -161,8 +160,6 @@ export const REPOSITORIES_QUERY = gql`
$query: String
$indexed: Boolean
$notIndexed: Boolean
$embedded: Boolean
$notEmbedded: Boolean
$failedFetch: Boolean
$corrupted: Boolean
$cloneStatus: CloneStatus
@ -178,8 +175,6 @@ export const REPOSITORIES_QUERY = gql`
query: $query
indexed: $indexed
notIndexed: $notIndexed
embedded: $embedded
notEmbedded: $notEmbedded
failedFetch: $failedFetch
corrupted: $corrupted
cloneStatus: $cloneStatus
@ -344,7 +339,6 @@ export const RECLONE_REPOSITORY_MUTATION = gql`
/**
* Fetches the site and its configuration.
*
* @returns Observable that emits the site
*/
export function fetchSite(): Observable<SiteResult['site']> {
@ -480,7 +474,6 @@ export function fetchAllConfigAndSettings(): Observable<AllConfig> {
/**
* Updates the site's configuration.
*
* @returns An observable indicating whether or not a service restart is
* required for the update to be applied.
*/
@ -753,7 +746,6 @@ export const STATUS_AND_REPO_STATS = gql`
failedFetch
corrupted
indexed
embedded
}
statusMessages {
... on GitUpdatesDisabled {

View File

@ -3,9 +3,7 @@ import { Navigate, useLocation } from 'react-router-dom'
import { lazyComponent } from '@sourcegraph/shared/src/util/lazyComponent'
import { FeedbackBadge } from '@sourcegraph/wildcard'
import { isEmbeddingsEnabled } from '../cody/isCodyEnabled'
import type { BatchSpecsPageProps } from '../enterprise/batches/BatchSpecsPage'
import { CodeIntelConfigurationPolicyPage } from '../enterprise/codeintel/configuration/pages/CodeIntelConfigurationPolicyPage'
import { SHOW_BUSINESS_FEATURES } from '../enterprise/dotcom/productSubscriptions/features'
import { OwnAnalyticsPage } from '../enterprise/own/admin-ui/OwnAnalyticsPage'
import type { SiteAdminRolesPageProps } from '../enterprise/rbac/SiteAdminRolesPage'
@ -185,15 +183,6 @@ const CodeInsightsJobsPage = lazyComponent(
)
const OwnStatusPage = lazyComponent(() => import('../enterprise/own/admin-ui/OwnStatusPage'), 'OwnStatusPage')
const SiteAdminCodyPage = lazyComponent(
() => import('../enterprise/site-admin/cody/SiteAdminCodyPage'),
'SiteAdminCodyPage'
)
const CodyConfigurationPage = lazyComponent(
() => import('../enterprise/cody/configuration/pages/CodyConfigurationPage'),
'CodyConfigurationPage'
)
export const otherSiteAdminRoutes: readonly SiteAdminAreaRoute[] = [
{
path: '/',
@ -488,31 +477,6 @@ export const otherSiteAdminRoutes: readonly SiteAdminAreaRoute[] = [
condition: () => Boolean(window.context?.executorsEnabled),
},
// Cody configuration
{
exact: true,
path: '/cody',
render: () => <Navigate to="/site-admin/embeddings" />,
condition: isEmbeddingsEnabled,
},
{
exact: true,
path: '/embeddings',
render: props => <SiteAdminCodyPage {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />,
condition: isEmbeddingsEnabled,
},
{
exact: true,
path: '/embeddings/configuration',
render: props => <CodyConfigurationPage {...props} />,
condition: isEmbeddingsEnabled,
},
{
path: '/embeddings/configuration/:id',
render: props => <CodeIntelConfigurationPolicyPage {...props} domain="embeddings" />,
condition: isEmbeddingsEnabled,
},
// rbac-related routes
{
path: '/roles',

View File

@ -9,7 +9,6 @@ import PackageVariantIcon from 'mdi-react/PackageVariantIcon'
import SourceRepositoryIcon from 'mdi-react/SourceRepositoryIcon'
import { BatchChangesIcon } from '../batches/icons'
import { CodyPageIcon } from '../cody/chat/CodyPageIcon'
import { SHOW_BUSINESS_FEATURES } from '../enterprise/dotcom/productSubscriptions/features'
import { checkRequestAccessAllowed } from '../util/checkRequestAccessAllowed'
@ -281,24 +280,6 @@ const codeIntelGroup: SiteAdminSideBarGroup = {
condition: ({ license }) => license.isCodeSearchEnabled,
}
export const codyGroup: SiteAdminSideBarGroup = {
header: { label: 'Cody', icon: CodyPageIcon },
items: [
{
label: 'Embeddings jobs',
to: '/site-admin/embeddings',
exact: true,
condition: () => window.context?.embeddingsEnabled,
},
{
label: 'Embeddings policies',
to: '/site-admin/embeddings/configuration',
condition: () => window.context?.embeddingsEnabled,
},
],
condition: () => Boolean(window.context?.codyEnabled && window.context?.embeddingsEnabled),
}
const usersGroup: SiteAdminSideBarGroup = {
header: {
label: 'Users & auth',
@ -381,7 +362,6 @@ export const siteAdminSidebarGroups: SiteAdminSideBarGroups = [
configurationGroup,
repositoriesGroup,
codeIntelGroup,
codyGroup,
usersGroup,
executorsGroup,
maintenanceGroup,

View File

@ -244,8 +244,6 @@ type JSContext struct {
SearchAggregationEnabled bool `json:"searchAggregationEnabled"`
OwnEnabled bool `json:"ownEnabled"`
EmbeddingsEnabled bool `json:"embeddingsEnabled"`
RedirectUnsupportedBrowser bool `json:"RedirectUnsupportedBrowser"`
ProductResearchPageEnabled bool `json:"productResearchPageEnabled"`
@ -453,8 +451,6 @@ func NewJSContextFromRequest(req *http.Request, db database.DB) JSContext {
SearchAggregationEnabled: true,
OwnEnabled: true,
EmbeddingsEnabled: conf.EmbeddingsEnabled(),
ProductResearchPageEnabled: conf.ProductResearchPageEnabled(),
ExperimentalFeatures: conf.ExperimentalFeatures(),
@ -500,12 +496,11 @@ func NewJSContextFromRequest(req *http.Request, db database.DB) JSContext {
context.ExperimentalFeatures.SearchJobs = pointers.Ptr(false)
}
// If the license a Sourcegraph instance is running under does not support Cody features
// we force disable related features (embeddings etc).
// If the license a Sourcegraph instance is running under does not support Cody features,
// we force disable related features.
if !context.LicenseInfo.Features.Cody {
context.CodyEnabled = false
context.CodyEnabledForCurrentUser = false
context.EmbeddingsEnabled = false
}
return context