From f0c9551f56cff98e251f3c3f19cb30051e5cfd8f Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Thu, 4 Jul 2024 22:50:03 +0200 Subject: [PATCH] feat(svelte): Add Cody chat sidebar (#63638) This commit adds the React version of the cody chat sidebar to the Svelte web app. I used @vovakulikov's work in the React app as guidance. I'm sure we'll have to do follow up work, but it's a start. This PR also fixes `sg start web-sveltekit-standalone` (because I originally thought that running it from `sourcegraph.test` is necessary to make auth work). ## Test plan Manual testing. https://github.com/sourcegraph/sourcegraph/assets/179026/3fa3f2ea-b23e-44ca-a75a-0089bf07fb2b --- client/web-sveltekit/BUILD.bazel | 11 ++- client/web-sveltekit/package.json | 1 + .../src/lib/cody/CodySidebar.gql | 4 + .../src/lib/cody/CodySidebar.svelte | 73 +++++++++++++++ .../src/lib/cody/CodySidebarChat.svelte | 93 +++++++++++++++++++ .../src/lib/repo/OpenCodyAction.svelte | 23 +++++ client/web-sveltekit/src/lib/repo/stores.ts | 3 + .../(validrev)/(code)/+layout.svelte | 26 +++++- .../(code)/-/blob/[...path]/FileView.gql | 18 ++-- .../(code)/-/blob/[...path]/FileView.svelte | 2 + .../(code)/-/blob/[...path]/page.gql | 4 +- .../(code)/-/tree/[...path]/+page.svelte | 2 + .../src/routes/[...repo=reporev]/layout.gql | 1 + client/web-sveltekit/vite.config.ts | 11 ++- pnpm-lock.yaml | 3 + sg.config.yaml | 7 ++ 16 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 client/web-sveltekit/src/lib/cody/CodySidebar.gql create mode 100644 client/web-sveltekit/src/lib/cody/CodySidebar.svelte create mode 100644 client/web-sveltekit/src/lib/cody/CodySidebarChat.svelte create mode 100644 client/web-sveltekit/src/lib/repo/OpenCodyAction.svelte diff --git a/client/web-sveltekit/BUILD.bazel b/client/web-sveltekit/BUILD.bazel index d8d0d23a06e..72c17da9fbf 100644 --- a/client/web-sveltekit/BUILD.bazel +++ b/client/web-sveltekit/BUILD.bazel @@ -64,6 +64,8 @@ BUILD_DEPS = [ "//:node_modules/@reach/menu-button", "//:node_modules/@types/lodash", "//:node_modules/@types/node", + "//:node_modules/@types/react", + "//:node_modules/@types/react-dom", "//:node_modules/classnames", "//:node_modules/copy-to-clipboard", "//:node_modules/date-fns", @@ -71,11 +73,15 @@ BUILD_DEPS = [ "//:node_modules/lodash-es", "//:node_modules/open-color", "//:node_modules/path-browserify", + "//:node_modules/react", + "//:node_modules/react-dom", "//:node_modules/react-resizable", "//:node_modules/rxjs", "//:node_modules/uuid", ":node_modules/@faker-js/faker", ":node_modules/@floating-ui/dom", + ":node_modules/@fontsource-variable/inter", + ":node_modules/@fontsource-variable/roboto-mono", ":node_modules/@graphql-codegen/cli", ":node_modules/@graphql-codegen/near-operation-file-preset", ":node_modules/@graphql-codegen/typed-document-node", @@ -92,19 +98,18 @@ BUILD_DEPS = [ ":node_modules/@sourcegraph/branded", ":node_modules/@sourcegraph/client-api", ":node_modules/@sourcegraph/common", - ":node_modules/@fontsource-variable/inter", - ":node_modules/@fontsource-variable/roboto-mono", ":node_modules/@sourcegraph/http-client", ":node_modules/@sourcegraph/shared", + ":node_modules/@sourcegraph/telemetry", ":node_modules/@sourcegraph/web", ":node_modules/@sourcegraph/wildcard", - ":node_modules/@sourcegraph/telemetry", ":node_modules/@storybook/svelte", ":node_modules/@sveltejs/adapter-static", ":node_modules/@sveltejs/kit", ":node_modules/@sveltejs/vite-plugin-svelte", ":node_modules/@types/prismjs", ":node_modules/@urql/core", + ":node_modules/cody-web-experimental", ":node_modules/fzf", ":node_modules/graphql", ":node_modules/hotkeys-js", diff --git a/client/web-sveltekit/package.json b/client/web-sveltekit/package.json index bb9b803529e..efb28890961 100644 --- a/client/web-sveltekit/package.json +++ b/client/web-sveltekit/package.json @@ -92,6 +92,7 @@ "@sourcegraph/wildcard": "workspace:*", "@storybook/test": "^8.0.5", "@urql/core": "^4.2.3", + "cody-web-experimental": "^0.1.4", "copy-to-clipboard": "^3.3.1", "fzf": "^0.5.2", "highlight.js": "^10.0.0", diff --git a/client/web-sveltekit/src/lib/cody/CodySidebar.gql b/client/web-sveltekit/src/lib/cody/CodySidebar.gql new file mode 100644 index 00000000000..4beff1bd72b --- /dev/null +++ b/client/web-sveltekit/src/lib/cody/CodySidebar.gql @@ -0,0 +1,4 @@ +fragment CodySidebar_ResolvedRevision on Repository { + id + name +} diff --git a/client/web-sveltekit/src/lib/cody/CodySidebar.svelte b/client/web-sveltekit/src/lib/cody/CodySidebar.svelte new file mode 100644 index 00000000000..e4e75ff719e --- /dev/null +++ b/client/web-sveltekit/src/lib/cody/CodySidebar.svelte @@ -0,0 +1,73 @@ + + +
+
+

+ Cody + Experimental +

+ + + +
+ {#if $user} + {#await import('./CodySidebarChat.svelte')} + + {:then module} + + {/await} + {:else} + + Cody is only available to signed-in users. + Sign in to use Cody. + + {/if} +
+ + diff --git a/client/web-sveltekit/src/lib/cody/CodySidebarChat.svelte b/client/web-sveltekit/src/lib/cody/CodySidebarChat.svelte new file mode 100644 index 00000000000..6ba1fbe1b44 --- /dev/null +++ b/client/web-sveltekit/src/lib/cody/CodySidebarChat.svelte @@ -0,0 +1,93 @@ + + +
+ + diff --git a/client/web-sveltekit/src/lib/repo/OpenCodyAction.svelte b/client/web-sveltekit/src/lib/repo/OpenCodyAction.svelte new file mode 100644 index 00000000000..560e3c32219 --- /dev/null +++ b/client/web-sveltekit/src/lib/repo/OpenCodyAction.svelte @@ -0,0 +1,23 @@ + + + + + + + diff --git a/client/web-sveltekit/src/lib/repo/stores.ts b/client/web-sveltekit/src/lib/repo/stores.ts index 27c3ceae1cd..d65ac2ff1f3 100644 --- a/client/web-sveltekit/src/lib/repo/stores.ts +++ b/client/web-sveltekit/src/lib/repo/stores.ts @@ -1,6 +1,7 @@ import { memoize } from 'lodash' import { writable, type Writable } from 'svelte/store' +import { createLocalWritable } from '$lib/stores' import { createEmptySingleSelectTreeState, type TreeState } from '$lib/TreeView' /** @@ -11,3 +12,5 @@ export const getSidebarFileTreeStateForRepo = memoize( (_repoName: string): Writable => writable(createEmptySingleSelectTreeState()), repoName => repoName ) + +export const rightPanelOpen = createLocalWritable('repo.right-panel.open', false) diff --git a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.svelte b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.svelte index d16dff5c22c..372a6e5183c 100644 --- a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.svelte +++ b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/+layout.svelte @@ -41,6 +41,7 @@ import { afterNavigate, goto } from '$app/navigation' import { page } from '$app/stores' + import CodySidebar from '$lib/cody/CodySidebar.svelte' import { isErrorLike, SourcegraphURL } from '$lib/common' import { openFuzzyFinder } from '$lib/fuzzyfinder/FuzzyFinderContainer.svelte' import { filesHotkey } from '$lib/fuzzyfinder/keys' @@ -50,6 +51,7 @@ import { fetchSidebarFileTree } from '$lib/repo/api/tree' import HistoryPanel from '$lib/repo/HistoryPanel.svelte' import LastCommit from '$lib/repo/LastCommit.svelte' + import { rightPanelOpen } from '$lib/repo/stores' import TabPanel from '$lib/TabPanel.svelte' import Tabs from '$lib/Tabs.svelte' import Tooltip from '$lib/Tooltip.svelte' @@ -249,8 +251,22 @@ - - + + + + + + {#if $rightPanelOpen} + + + ($rightPanelOpen = false)} + /> + + {/if} + @@ -184,6 +185,7 @@ {/if} + diff --git a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/blob/[...path]/page.gql b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/blob/[...path]/page.gql index ed7593c3b13..e44b44ca4b7 100644 --- a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/blob/[...path]/page.gql +++ b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/blob/[...path]/page.gql @@ -64,8 +64,8 @@ query BlobFileViewCodeGraphDataQuery($repoName: String!, $revspec: String!, $pat query BlobViewCodeGraphDataNextPage($codeGraphDataID: ID!, $after: String!) { node(id: $codeGraphDataID) { - ...on CodeGraphData { - occurrences(first: 10000, after: $after){ + ... on CodeGraphData { + occurrences(first: 10000, after: $after) { nodes { ...FileViewOccurrence } diff --git a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/tree/[...path]/+page.svelte b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/tree/[...path]/+page.svelte index 54f259a952d..313e386b203 100644 --- a/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/tree/[...path]/+page.svelte +++ b/client/web-sveltekit/src/routes/[...repo=reporev]/(validrev)/(code)/-/tree/[...path]/+page.svelte @@ -10,6 +10,7 @@ import Readme from '$lib/repo/Readme.svelte' import { createPromiseStore } from '$lib/utils' import { Alert } from '$lib/wildcard' + import OpenCodyAction from '$lib/repo/OpenCodyAction.svelte' import { getRepositoryPageContext } from '../../../../../context' @@ -37,6 +38,7 @@ + diff --git a/client/web-sveltekit/src/routes/[...repo=reporev]/layout.gql b/client/web-sveltekit/src/routes/[...repo=reporev]/layout.gql index e59041d424e..a0b48315f7d 100644 --- a/client/web-sveltekit/src/routes/[...repo=reporev]/layout.gql +++ b/client/web-sveltekit/src/routes/[...repo=reporev]/layout.gql @@ -34,4 +34,5 @@ fragment ResolvedRepository on Repository { } ...RepoPage_ResolvedRevision ...BlobPage_ResolvedRevision + ...CodySidebar_ResolvedRevision } diff --git a/client/web-sveltekit/vite.config.ts b/client/web-sveltekit/vite.config.ts index a24c56300ea..5186d32cc20 100644 --- a/client/web-sveltekit/vite.config.ts +++ b/client/web-sveltekit/vite.config.ts @@ -72,18 +72,25 @@ export default defineConfig(({ mode }) => { }, }, server: { + // When running behind caddy we have to listen to a different host. + host: process.env.SK_HOST || 'localhost', // Allow setting the port via env variables to make it easier to integrate with // our existing caddy setup (which proxies requests to a specific port). port: process.env.SK_PORT ? +process.env.SK_PORT : undefined, - strictPort: !!process.env.SV_PORT, + strictPort: !!process.env.SK_PORT, 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|code-graph|batch-changes|settings)(/|$)': + '^(/sign-(in|out)|/.assets|/-|/.api|/.auth|/search/stream|/users|/notebooks|/insights|/batch-changes)|/-/(raw|compare|own|code-graph|batch-changes|settings)(/|$)': { target: process.env.SOURCEGRAPH_API_URL || 'https://sourcegraph.sourcegraph.com', changeOrigin: true, secure: false, + headers: { + // This needs to be set to make the cody sidebar work, which doesn't use the web graphql client work. + // todo(fkling): Figure out how the React app makes this work without this header. + 'X-Requested-With': 'Sourcegraph', + }, }, }, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eebd67d2545..7b47bffd8d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1593,6 +1593,9 @@ importers: '@urql/core': specifier: ^4.2.3 version: 4.2.3(graphql@15.4.0) + cody-web-experimental: + specifier: ^0.1.4 + version: 0.1.4 copy-to-clipboard: specifier: ^3.3.1 version: 3.3.1 diff --git a/sg.config.yaml b/sg.config.yaml index 5536ae849ce..34ba8af01f3 100644 --- a/sg.config.yaml +++ b/sg.config.yaml @@ -510,6 +510,12 @@ commands: install: | pnpm install pnpm generate + env: + SOURCEGRAPH_API_URL: https://sourcegraph.sourcegraph.com + # The SvelteKit app uses this environment variable to determine where + # to store the generated assets. We don't need to store them in a different + # place in standalone mode. + DEPLOY_TYPE: "" web-sveltekit-prod-watch: description: Builds the prod version of the SvelteKit web app and rebuilds on changes @@ -1789,6 +1795,7 @@ commandsets: - caddy env: SK_PORT: 3080 + SK_HOST: 127.0.0.1 # For testing our OpenTelemetry stack otel: