mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:51:43 +00:00
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:
parent
8b6d4f8513
commit
896819f811
@ -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,
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -114,9 +114,6 @@
|
||||
.repo-icon {
|
||||
color: var(--text-disabled);
|
||||
}
|
||||
.embedding-icon-no-embeddings {
|
||||
color: var(--gray-07);
|
||||
}
|
||||
}
|
||||
|
||||
.not-included-in-context:hover {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
`
|
||||
|
||||
@ -41,7 +41,6 @@ const emptyPolicy: CodeIntelligenceConfigurationPolicyFields = {
|
||||
indexingEnabled: false,
|
||||
indexCommitMaxAgeHours: null,
|
||||
indexIntermediateCommits: false,
|
||||
embeddingsEnabled: false,
|
||||
}
|
||||
|
||||
export const usePolicyConfigurationByID = (id: string): UsePolicyConfigResult => {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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>
|
||||
)
|
||||
|
||||
@ -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'
|
||||
}
|
||||
|
||||
@ -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>
|
||||
)
|
||||
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -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>
|
||||
)
|
||||
}
|
||||
@ -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>
|
||||
)
|
||||
@ -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,
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
.badge-wrapper {
|
||||
min-width: 90px;
|
||||
}
|
||||
|
||||
.error-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.alert-overflow {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@ -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>
|
||||
)
|
||||
@ -1,3 +0,0 @@
|
||||
.schedule-button {
|
||||
height: 2.375rem;
|
||||
}
|
||||
@ -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>
|
||||
)
|
||||
@ -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)
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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[]
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -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
|
||||
|
||||
@ -43,8 +43,3 @@
|
||||
min-height: 16px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.embeddings {
|
||||
background-color: var(--success) !important;
|
||||
color: var(--white) !important;
|
||||
}
|
||||
|
||||
@ -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)}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user