From d8bb1b3a3da84c9be661b96b0542f957ecb353eb Mon Sep 17 00:00:00 2001 From: Beatrix Date: Tue, 10 Sep 2024 15:07:16 -0700 Subject: [PATCH 1/9] feat(onboarding): add endpoint selection UI for non-VSCode IDEs This change adds a new UI flow for non-VSCode IDEs (e.g. JetBrains IDEs) that allows users to select a Sourcegraph instance from their previously used endpoints. The key changes are: - Add a dropdown to select the Sourcegraph instance from the user's endpoint history - Add a button to sign in to the selected instance - Add a button to add a new Sourcegraph instance if the desired one is not in the history The endpoint history is stored and retrieved using the `getEndpointHistory()` and `handleEndpointAuthRequest()` functions added in the `auth.ts` file. This change ensures a smooth onboarding experience for users of non-VSCode IDEs by providing a familiar way to select and authenticate with their Sourcegraph instance. The `ConfigurationSubsetForWebview` interface in `protocol.ts` has been updated to include the `endpointHistory` field. --- pnpm-lock.yaml | 308 +++++++++++++++++- vscode/package.json | 83 ++++- vscode/src/auth/auth.ts | 43 ++- vscode/src/chat/chat-view/ChatController.ts | 25 +- vscode/src/chat/protocol.ts | 1 + vscode/webviews/App.tsx | 1 + vscode/webviews/OnboardingExperiment.tsx | 73 ++++- .../webviews/components/shadcn/ui/select.tsx | 33 ++ 8 files changed, 509 insertions(+), 58 deletions(-) create mode 100644 vscode/webviews/components/shadcn/ui/select.tsx diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0cb210afec..313fc8e0de3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -468,6 +468,9 @@ importers: '@radix-ui/react-popover': specifier: ^1.0.7 version: 1.0.7(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-select': + specifier: ^2.1.1 + version: 2.1.1(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.79)(react@18.2.0) @@ -3752,6 +3755,10 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: true + /@radix-ui/number@1.1.0: + resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + dev: false + /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: @@ -3811,6 +3818,26 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-arrow@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==} peerDependencies: @@ -4086,6 +4113,30 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.37)(react@18.2.0): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: @@ -4114,6 +4165,19 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-focus-guards@1.1.0(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.79 + react: 18.2.0 + dev: false + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: @@ -4160,6 +4224,28 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-form@0.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-1/oVYPDjbFILOLIarcGcMKo+y6SbTVT/iUKVEw59CF4offwZgBgC3ZOeSBewjqU0vdA6FWTPWTN63obj55S/tQ==} peerDependencies: @@ -4314,6 +4400,35 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-popper@1.2.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@floating-ui/react-dom': 2.0.9(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/rect': 1.1.0 + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} peerDependencies: @@ -4356,6 +4471,27 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-portal@1.1.1(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: @@ -4511,6 +4647,46 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-select@2.1.1(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + aria-hidden: 1.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.7(@types/react@18.2.79)(react@18.2.0) + dev: false + /@radix-ui/react-slot@1.0.2(@types/react@18.2.37)(react@18.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: @@ -4742,6 +4918,20 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@types/react': 18.2.79 + react: 18.2.0 + dev: false + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.37)(react@18.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: @@ -4783,6 +4973,19 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-use-previous@1.1.0(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.79 + react: 18.2.0 + dev: false + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.79)(react@18.2.0): resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: @@ -4798,6 +5001,20 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-use-rect@1.1.0(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/rect': 1.1.0 + '@types/react': 18.2.79 + react: 18.2.0 + dev: false + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.79)(react@18.2.0): resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: @@ -4813,6 +5030,20 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-use-size@1.1.0(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.2.0) + '@types/react': 18.2.79 + react: 18.2.0 + dev: false + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: @@ -4834,12 +5065,36 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.79 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: '@babel/runtime': 7.24.5 dev: false + /@radix-ui/rect@1.1.0: + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + dev: false + /@rollup/pluginutils@5.1.0: resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} @@ -7151,7 +7406,7 @@ packages: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} engines: {node: '>=10'} dependencies: - tslib: 2.1.0 + tslib: 2.7.0 dev: false /aria-query@5.1.3: @@ -7235,7 +7490,7 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} dependencies: - tslib: 2.1.0 + tslib: 2.7.0 dev: true /astral-regex@2.0.0: @@ -8733,7 +8988,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.1.0 + tslib: 2.7.0 dev: true /dotenv-expand@10.0.0: @@ -11378,7 +11633,7 @@ packages: /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.1.0 + tslib: 2.7.0 dev: true /lowlight@2.9.0: @@ -12421,7 +12676,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.1.0 + tslib: 2.7.0 dev: true /nocache@3.0.4: @@ -13624,7 +13879,7 @@ packages: '@types/react': 18.2.37 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.37)(react@18.2.0) - tslib: 2.1.0 + tslib: 2.7.0 dev: false /react-remove-scroll-bar@2.3.6(@types/react@18.2.79)(react@18.2.0): @@ -13640,7 +13895,7 @@ packages: '@types/react': 18.2.79 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.2.0) - tslib: 2.1.0 + tslib: 2.7.0 dev: false /react-remove-scroll@2.5.5(@types/react@18.2.37)(react@18.2.0): @@ -13657,7 +13912,7 @@ packages: react: 18.2.0 react-remove-scroll-bar: 2.3.6(@types/react@18.2.37)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.37)(react@18.2.0) - tslib: 2.1.0 + tslib: 2.7.0 use-callback-ref: 1.3.2(@types/react@18.2.37)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.37)(react@18.2.0) dev: false @@ -13676,7 +13931,26 @@ packages: react: 18.2.0 react-remove-scroll-bar: 2.3.6(@types/react@18.2.79)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.2.0) - tslib: 2.1.0 + tslib: 2.7.0 + use-callback-ref: 1.3.2(@types/react@18.2.79)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.2.0) + dev: false + + /react-remove-scroll@2.5.7(@types/react@18.2.79)(react@18.2.0): + resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.79 + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@types/react@18.2.79)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.2.0) + tslib: 2.7.0 use-callback-ref: 1.3.2(@types/react@18.2.79)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.2.0) dev: false @@ -13695,7 +13969,7 @@ packages: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /react-style-singleton@2.2.1(@types/react@18.2.79)(react@18.2.0): @@ -13712,7 +13986,7 @@ packages: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /react@18.2.0: @@ -13822,7 +14096,7 @@ packages: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.1.0 + tslib: 2.7.0 dev: true /redent@3.0.0: @@ -14412,7 +14686,7 @@ packages: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} dependencies: dot-case: 3.0.4 - tslib: 2.1.0 + tslib: 2.7.0 dev: true /snapdragon-node@2.1.1: @@ -15738,7 +16012,7 @@ packages: dependencies: '@types/react': 18.2.37 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /use-callback-ref@1.3.2(@types/react@18.2.79)(react@18.2.0): @@ -15753,7 +16027,7 @@ packages: dependencies: '@types/react': 18.2.79 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /use-sidecar@1.1.2(@types/react@18.2.37)(react@18.2.0): @@ -15769,7 +16043,7 @@ packages: '@types/react': 18.2.37 detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /use-sidecar@1.1.2(@types/react@18.2.79)(react@18.2.0): @@ -15785,7 +16059,7 @@ packages: '@types/react': 18.2.79 detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.1.0 + tslib: 2.7.0 dev: false /use@3.1.1: diff --git a/vscode/package.json b/vscode/package.json index 9c84234b0bb..f20e25c1759 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -55,7 +55,14 @@ "version-bump:patch": "RELEASE_TYPE=patch ts-node-transpile-only ./scripts/version-bump.ts", "version-bump:dry-run": "RELEASE_TYPE=prerelease ts-node-transpile-only ./scripts/version-bump.ts" }, - "categories": ["AI", "Chat", "Programming Languages", "Machine Learning", "Snippets", "Education"], + "categories": [ + "AI", + "Chat", + "Programming Languages", + "Machine Learning", + "Snippets", + "Education" + ], "keywords": [ "cody", "codey", @@ -119,7 +126,11 @@ }, "main": "./dist/extension.node.js", "browser": "./dist/extension.web.js", - "activationEvents": ["onLanguage", "onStartupFinished", "onWebviewPanel:cody.editorPanel"], + "activationEvents": [ + "onLanguage", + "onStartupFinished", + "onWebviewPanel:cody.editorPanel" + ], "contributes": { "walkthroughs": [ { @@ -730,13 +741,17 @@ }, { "command": "cody.supercompletion.jumpTo", - "args": ["next"], + "args": [ + "next" + ], "key": "shift+ctrl+down", "when": "cody.activated && !editorReadonly && cody.hasActionableSupercompletion" }, { "command": "cody.supercompletion.jumpTo", - "args": ["previous"], + "args": [ + "previous" + ], "key": "shift+ctrl+up", "when": "cody.activated && !editorReadonly && cody.hasActionableSupercompletion" } @@ -998,12 +1013,20 @@ "order": 2, "type": "string", "markdownDescription": "A Git repository URL to use instead of allowing Cody to infer the Git repository from the workspace.", - "examples": ["https://github.com/sourcegraph/cody", "ssh://git@github.com/sourcegraph/cody"] + "examples": [ + "https://github.com/sourcegraph/cody", + "ssh://git@github.com/sourcegraph/cody" + ] }, "cody.useContext": { "order": 99, "type": "string", - "enum": ["embeddings", "keyword", "blended", "none"], + "enum": [ + "embeddings", + "keyword", + "blended", + "none" + ], "default": "blended", "markdownDescription": "Controls which context providers Cody uses for chat, commands and inline edits. Use 'blended' for best results. For debugging other context sources, 'embeddings' will use an embeddings-based index if available. 'keyword' will use a search-based index. 'none' will not use embeddings or search-based indexes." }, @@ -1055,12 +1078,18 @@ "order": 6, "type": "string", "markdownDescription": "A custom instruction to be included at the start of all chat messages (e.g. \"Answer all my questions in Spanish.\")", - "examples": ["Answer all my questions in Spanish."] + "examples": [ + "Answer all my questions in Spanish." + ] }, "cody.chat.defaultLocation": { "order": 6, "type": "string", - "enum": ["sticky", "sidebar", "editor"], + "enum": [ + "sticky", + "sidebar", + "editor" + ], "markdownDescription": "Controls where the Cody chat view opens when the user invokes the `Cody: New Chat` command, or the Alt+L and Alt+/ shortcuts.", "enumDescriptions": [ "Opens in the last-activated view location, which is set whenever the user explicitly chooses to open chat in a given location", @@ -1073,7 +1102,9 @@ "order": 7, "type": "string", "markdownDescription": "A custom instruction to be included at the end of all instructions for edit commands (e.g. \"Write all unit tests with Jest instead of detected framework.\")", - "examples": ["Write all unit tests with Jest instead of detected framework."] + "examples": [ + "Write all unit tests with Jest instead of detected framework." + ] }, "cody.codeActions.enabled": { "order": 11, @@ -1119,8 +1150,14 @@ "cody.telemetry.level": { "order": 99, "type": "string", - "enum": ["all", "off"], - "enumDescriptions": ["Sends usage data and errors.", "Disables all extension telemetry."], + "enum": [ + "all", + "off" + ], + "enumDescriptions": [ + "Sends usage data and errors.", + "Disables all extension telemetry." + ], "markdownDescription": "Controls the telemetry about Cody usage and errors. See [Cody usage and privacy notice](https://about.sourcegraph.com/terms/cody-notice).", "default": "all" }, @@ -1149,7 +1186,11 @@ "cody.autocomplete.advanced.model": { "type": "string", "default": null, - "enum": [null, "starcoder-16b", "starcoder-7b"], + "enum": [ + null, + "starcoder-16b", + "starcoder-7b" + ], "markdownDescription": "Overwrite the model used for code autocompletion inference. This is only supported with the `fireworks` provider" }, "cody.autocomplete.completeSuggestWidgetSelection": { @@ -1169,7 +1210,10 @@ }, "cody.experimental.foldingRanges": { "type": "string", - "enum": ["lsp", "indentation-based"], + "enum": [ + "lsp", + "indentation-based" + ], "enumDescriptions": [ "Use folding ranges that are enabled by default in VS Code, and are usually powered by LSP", "Use custom implementation of folding ranges that is indentation based. This is the implementation that is used by other Cody clients like the JetBrains plugin" @@ -1180,7 +1224,13 @@ "cody.autocomplete.experimental.graphContext": { "type": "string", "default": null, - "enum": [null, "bfg", "bfg-mixed", "tsc", "tsc-mixed"], + "enum": [ + null, + "bfg", + "bfg-mixed", + "tsc", + "tsc-mixed" + ], "markdownDescription": "Use the code graph to retrieve context for autocomplete requests." }, "cody.autocomplete.experimental.fireworksOptions": { @@ -1355,7 +1405,9 @@ "untrustedWorkspaces": { "supported": "limited", "description": "Cody only uses providers (configured in `openctx.providers`) from trusted workspaces because providers may execute arbitrary code.", - "restrictedConfigurations": ["openctx.providers"] + "restrictedConfigurations": [ + "openctx.providers" + ] } }, "dependencies": { @@ -1376,6 +1428,7 @@ "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-form": "^0.1.0", "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", diff --git a/vscode/src/auth/auth.ts b/vscode/src/auth/auth.ts index 267e41a0df1..a429d186d65 100644 --- a/vscode/src/auth/auth.ts +++ b/vscode/src/auth/auth.ts @@ -63,27 +63,34 @@ export async function showSignInMenu( default: { // Auto log user if token for the selected instance was found in secret const selectedEndpoint = item.uri - const token = await secretStorage.get(selectedEndpoint) - let authStatus = await authProvider.instance!.auth({ - endpoint: selectedEndpoint, - token: token || null, - }) - if (!authStatus?.authenticated) { - const newToken = await showAccessTokenInputBox(item.uri) - if (!newToken) { - return - } - authStatus = await authProvider.instance!.auth({ - endpoint: selectedEndpoint, - token: newToken || null, - }) - } + await handleEndpointAuthRequest(selectedEndpoint) await showAuthResultMessage(selectedEndpoint, authStatus) logDebug('AuthProvider:signinMenu', mode, selectedEndpoint) } } } +export async function handleEndpointAuthRequest(endpointURI: string): Promise { + if (!endpointURI) { + return + } + const token = await secretStorage.get(endpointURI) + let authStatus = await authProvider.instance!.auth({ + endpoint: endpointURI, + token: token || null, + }) + if (!authStatus?.authenticated) { + const newToken = await showAccessTokenInputBox(endpointURI) + if (!newToken) { + return + } + authStatus = await authProvider.instance!.auth({ + endpoint: endpointURI, + token: newToken || null, + }) + } +} + interface LoginMenuItem { id: string label: string @@ -102,8 +109,12 @@ function getItemLabel(uri: string, current: boolean): string { return `${icon}${uri}` } +export function getEndpointHistory(): string[] { + return localStorage.getEndpointHistory()?.reverse() ?? [] +} + async function showAuthMenu(type: AuthMenuType): Promise { - const endpointHistory = localStorage.getEndpointHistory() ?? [] + const endpointHistory = getEndpointHistory() // Create option items const historySize = endpointHistory?.length diff --git a/vscode/src/chat/chat-view/ChatController.ts b/vscode/src/chat/chat-view/ChatController.ts index 2aa5c18052c..151c58b1038 100644 --- a/vscode/src/chat/chat-view/ChatController.ts +++ b/vscode/src/chat/chat-view/ChatController.ts @@ -66,7 +66,12 @@ import { map } from 'observable-fns' import type { URI } from 'vscode-uri' import { version as VSCEVersion } from '../../../package.json' import { View } from '../../../webviews/tabs/types' -import { redirectToEndpointLogin, showSignOutMenu } from '../../auth/auth' +import { + getEndpointHistory, + handleEndpointAuthRequest, + redirectToEndpointLogin, + showSignOutMenu, +} from '../../auth/auth' import { closeAuthProgressIndicator, startAuthProgressIndicator, @@ -471,11 +476,16 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv } break } - if (message.authKind === 'signin' && message.endpoint && message.value) { - await authProvider.instance!.auth({ - endpoint: message.endpoint, - token: message.value, - }) + if (message.authKind === 'signin' && message.endpoint) { + // Login with token provided by the user in webview. + if (message.value) { + await authProvider.instance!.auth({ + endpoint: message.endpoint, + token: message.value, + }) + } else { + handleEndpointAuthRequest(message.endpoint) + } break } if (message.authKind === 'signout') { @@ -531,7 +541,7 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv const sidebarViewOnly = this.extensionClient.capabilities?.webviewNativeConfig?.view === 'single' const isEditorViewType = this.webviewPanelOrView?.viewType === 'cody.editorPanel' const webviewType = isEditorViewType && !sidebarViewOnly ? 'editor' : 'sidebar' - + const endpointHistory = getEndpointHistory() return { agentIDE: config.agentIDE ?? CodyIDE.VSCode, agentExtensionVersion: config.isRunningInsideAgent @@ -544,6 +554,7 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv webviewType, multipleWebviewsEnabled: !sidebarViewOnly, internalDebugContext: config.internalDebugContext, + endpointHistory, } } diff --git a/vscode/src/chat/protocol.ts b/vscode/src/chat/protocol.ts index 176d878a887..12a71483a73 100644 --- a/vscode/src/chat/protocol.ts +++ b/vscode/src/chat/protocol.ts @@ -283,6 +283,7 @@ export interface ConfigurationSubsetForWebview webviewType?: WebviewType | undefined | null // Whether support running multiple webviews (e.g. sidebar w/ multiple editor panels). multipleWebviewsEnabled?: boolean | undefined | null + endpointHistory?: string[] | undefined | null } /** diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index 57f11e9a26e..79af12e7d7f 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -202,6 +202,7 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc uiKindIsWeb={config.config.uiKindIsWeb} vscodeAPI={vscodeAPI} codyIDE={config.config.agentIDE ?? CodyIDE.VSCode} + endpointHistory={config.config.endpointHistory ?? []} /> ) : ( diff --git a/vscode/webviews/OnboardingExperiment.tsx b/vscode/webviews/OnboardingExperiment.tsx index 201ab56a31a..764d451d0af 100644 --- a/vscode/webviews/OnboardingExperiment.tsx +++ b/vscode/webviews/OnboardingExperiment.tsx @@ -10,8 +10,17 @@ import signInLogoGitLab from './sign-in-logo-gitlab.svg' import signInLogoGoogle from './sign-in-logo-google.svg' import type { VSCodeWrapper } from './utils/VSCodeApi' +import { useState } from 'react' import styles from './OnboardingExperiment.module.css' import { ClientSignInForm } from './components/ClientSignInForm' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from './components/shadcn/ui/select' import { useTelemetryRecorder } from './utils/telemetry' import { useConfig } from './utils/useConfig' @@ -20,6 +29,7 @@ interface LoginProps { uiKindIsWeb: boolean vscodeAPI: VSCodeWrapper codyIDE: CodyIDE + endpointHistory?: string[] } const WebLogin: React.FunctionComponent< @@ -70,14 +80,71 @@ export const LoginSimplified: React.FunctionComponent { const authStatus = useConfig().authStatus const telemetryRecorder = useTelemetryRecorder() - const otherSignInClick = (): void => { - vscodeAPI.postMessage({ command: 'auth', authKind: 'signin' }) + const otherSignInClick = (endpoint?: string): void => { + vscodeAPI.postMessage({ command: 'auth', authKind: 'signin', endpoint }) } const isNonVSCodeIDE = codyIDE !== CodyIDE.Web && codyIDE !== CodyIDE.VSCode const isCodyWebUI = (uiKindIsWeb || codyIDE === CodyIDE.Web) && !isNonVSCodeIDE + + const [selectedEndpoint, setSelectedEndpoint] = useState(endpointHistory?.[0]) + const [onboardingView, setOnboardingView] = useState(!selectedEndpoint) + + if (isNonVSCodeIDE && endpointHistory?.length && selectedEndpoint && !onboardingView) { + return ( +
+
+ Hi, I'm Cody +
+

Select a Sourcegraph Instance

+
+
+ + otherSignInClick()} + > + Sign In + +
+
+
+
+

Instance not on the list?

+ setOnboardingView(true)} + > + Add New Account + +
+
+
+ ) + } + return (
@@ -149,7 +216,7 @@ export const LoginSimplified: React.FunctionComponent otherSignInClick()} > Sign In to Your Enterprise Instance diff --git a/vscode/webviews/components/shadcn/ui/select.tsx b/vscode/webviews/components/shadcn/ui/select.tsx new file mode 100644 index 00000000000..60f72b0d52d --- /dev/null +++ b/vscode/webviews/components/shadcn/ui/select.tsx @@ -0,0 +1,33 @@ +import * as SelectPrimitive from '@radix-ui/react-select' +import { ChevronDownIcon } from 'lucide-react' +import React from 'react' +import { cn } from '../utils' + +const Select = SelectPrimitive.Select +const SelectContent = SelectPrimitive.Content +const SelectItem = SelectPrimitive.Item +const SelectGroup = SelectPrimitive.Group +const SelectLabel = SelectPrimitive.Label +const SelectValue = SelectPrimitive.Value +const SelectIcon = SelectPrimitive.Icon + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + + + +)) + +export { Select, SelectContent, SelectItem, SelectGroup, SelectLabel, SelectTrigger, SelectValue } From 8c43907f0fbb786945935afd468a68d48fbb1848 Mon Sep 17 00:00:00 2001 From: Beatrix Date: Wed, 11 Sep 2024 10:56:36 -0700 Subject: [PATCH 2/9] fix lint --- vscode/package.json | 82 +++++++++------------------------------------ 1 file changed, 15 insertions(+), 67 deletions(-) diff --git a/vscode/package.json b/vscode/package.json index bfd2759f1c3..5b3ca7a6b46 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -55,14 +55,7 @@ "version-bump:patch": "RELEASE_TYPE=patch ts-node-transpile-only ./scripts/version-bump.ts", "version-bump:dry-run": "RELEASE_TYPE=prerelease ts-node-transpile-only ./scripts/version-bump.ts" }, - "categories": [ - "AI", - "Chat", - "Programming Languages", - "Machine Learning", - "Snippets", - "Education" - ], + "categories": ["AI", "Chat", "Programming Languages", "Machine Learning", "Snippets", "Education"], "keywords": [ "cody", "codey", @@ -126,11 +119,7 @@ }, "main": "./dist/extension.node.js", "browser": "./dist/extension.web.js", - "activationEvents": [ - "onLanguage", - "onStartupFinished", - "onWebviewPanel:cody.editorPanel" - ], + "activationEvents": ["onLanguage", "onStartupFinished", "onWebviewPanel:cody.editorPanel"], "contributes": { "walkthroughs": [ { @@ -741,17 +730,13 @@ }, { "command": "cody.supercompletion.jumpTo", - "args": [ - "next" - ], + "args": ["next"], "key": "shift+ctrl+down", "when": "cody.activated && !editorReadonly && cody.hasActionableSupercompletion" }, { "command": "cody.supercompletion.jumpTo", - "args": [ - "previous" - ], + "args": ["previous"], "key": "shift+ctrl+up", "when": "cody.activated && !editorReadonly && cody.hasActionableSupercompletion" } @@ -1013,20 +998,12 @@ "order": 2, "type": "string", "markdownDescription": "A Git repository URL to use instead of allowing Cody to infer the Git repository from the workspace.", - "examples": [ - "https://github.com/sourcegraph/cody", - "ssh://git@github.com/sourcegraph/cody" - ] + "examples": ["https://github.com/sourcegraph/cody", "ssh://git@github.com/sourcegraph/cody"] }, "cody.useContext": { "order": 99, "type": "string", - "enum": [ - "embeddings", - "keyword", - "blended", - "none" - ], + "enum": ["embeddings", "keyword", "blended", "none"], "default": "blended", "markdownDescription": "Controls which context providers Cody uses for chat, commands and inline edits. Use 'blended' for best results. For debugging other context sources, 'embeddings' will use an embeddings-based index if available. 'keyword' will use a search-based index. 'none' will not use embeddings or search-based indexes." }, @@ -1078,18 +1055,12 @@ "order": 6, "type": "string", "markdownDescription": "A custom instruction to be included at the start of all chat messages (e.g. \"Answer all my questions in Spanish.\")", - "examples": [ - "Answer all my questions in Spanish." - ] + "examples": ["Answer all my questions in Spanish."] }, "cody.chat.defaultLocation": { "order": 6, "type": "string", - "enum": [ - "sticky", - "sidebar", - "editor" - ], + "enum": ["sticky", "sidebar", "editor"], "markdownDescription": "Controls where the Cody chat view opens when the user invokes the `Cody: New Chat` command, or the Alt+L and Alt+/ shortcuts.", "enumDescriptions": [ "Opens in the last-activated view location, which is set whenever the user explicitly chooses to open chat in a given location", @@ -1102,9 +1073,7 @@ "order": 7, "type": "string", "markdownDescription": "A custom instruction to be included at the end of all instructions for edit commands (e.g. \"Write all unit tests with Jest instead of detected framework.\")", - "examples": [ - "Write all unit tests with Jest instead of detected framework." - ] + "examples": ["Write all unit tests with Jest instead of detected framework."] }, "cody.codeActions.enabled": { "order": 11, @@ -1150,14 +1119,8 @@ "cody.telemetry.level": { "order": 99, "type": "string", - "enum": [ - "all", - "off" - ], - "enumDescriptions": [ - "Sends usage data and errors.", - "Disables all extension telemetry." - ], + "enum": ["all", "off"], + "enumDescriptions": ["Sends usage data and errors.", "Disables all extension telemetry."], "markdownDescription": "Controls the telemetry about Cody usage and errors. See [Cody usage and privacy notice](https://about.sourcegraph.com/terms/cody-notice).", "default": "all" }, @@ -1186,11 +1149,7 @@ "cody.autocomplete.advanced.model": { "type": "string", "default": null, - "enum": [ - null, - "starcoder-16b", - "starcoder-7b" - ], + "enum": [null, "starcoder-16b", "starcoder-7b"], "markdownDescription": "Overwrite the model used for code autocompletion inference. This is only supported with the `fireworks` provider" }, "cody.autocomplete.completeSuggestWidgetSelection": { @@ -1210,10 +1169,7 @@ }, "cody.experimental.foldingRanges": { "type": "string", - "enum": [ - "lsp", - "indentation-based" - ], + "enum": ["lsp", "indentation-based"], "enumDescriptions": [ "Use folding ranges that are enabled by default in VS Code, and are usually powered by LSP", "Use custom implementation of folding ranges that is indentation based. This is the implementation that is used by other Cody clients like the JetBrains plugin" @@ -1224,13 +1180,7 @@ "cody.autocomplete.experimental.graphContext": { "type": "string", "default": null, - "enum": [ - null, - "bfg", - "bfg-mixed", - "tsc", - "tsc-mixed" - ], + "enum": [null, "bfg", "bfg-mixed", "tsc", "tsc-mixed"], "markdownDescription": "Use the code graph to retrieve context for autocomplete requests." }, "cody.autocomplete.experimental.fireworksOptions": { @@ -1405,9 +1355,7 @@ "untrustedWorkspaces": { "supported": "limited", "description": "Cody only uses providers (configured in `openctx.providers`) from trusted workspaces because providers may execute arbitrary code.", - "restrictedConfigurations": [ - "openctx.providers" - ] + "restrictedConfigurations": ["openctx.providers"] } }, "dependencies": { From e8c7fc28d343b7e97daeae4c39b6a53e97f16484 Mon Sep 17 00:00:00 2001 From: Beatrix Date: Wed, 2 Oct 2024 18:06:28 -0700 Subject: [PATCH 3/9] Update component and add new section --- vscode/src/auth/auth.ts | 11 +++ vscode/src/chat/chat-view/ChatController.ts | 10 +- vscode/webviews/AuthPage.tsx | 95 +++++++++++++++++-- .../webviews/components/shadcn/ui/select.tsx | 15 ++- 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/vscode/src/auth/auth.ts b/vscode/src/auth/auth.ts index cde9ea97660..c74babbb670 100644 --- a/vscode/src/auth/auth.ts +++ b/vscode/src/auth/auth.ts @@ -110,6 +110,17 @@ export async function showSignInMenu( } } +export async function tryAuthenticateEndpoint(serverEndpoint: string): Promise { + const accessToken = (await secretStorage.getToken(serverEndpoint)) ?? '' + const tokenSource = await secretStorage.getTokenSource(serverEndpoint) + if (accessToken) { + await authProvider.validateAndStoreCredentials( + { serverEndpoint, accessToken, tokenSource }, + 'always-store' + ) + } +} + function getEndpointItemLabel(uri: string, isAuthenticated: boolean): string { const icon = isAuthenticated ? '$(check) ' : '' return isDotCom(uri) ? `${icon}Sourcegraph.com` : `${icon}${uri}` diff --git a/vscode/src/chat/chat-view/ChatController.ts b/vscode/src/chat/chat-view/ChatController.ts index aaeb19ac03c..57dbcc4caa3 100644 --- a/vscode/src/chat/chat-view/ChatController.ts +++ b/vscode/src/chat/chat-view/ChatController.ts @@ -79,7 +79,7 @@ import type { TelemetryEventParameters } from '@sourcegraph/telemetry' import { map } from 'observable-fns' import type { URI } from 'vscode-uri' import { View } from '../../../webviews/tabs/types' -import { redirectToEndpointLogin, showSignOutMenu } from '../../auth/auth' +import { redirectToEndpointLogin, showSignOutMenu, tryAuthenticateEndpoint } from '../../auth/auth' import { closeAuthProgressIndicator, startAuthProgressIndicator, @@ -437,6 +437,10 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv }) break } + if (message.authKind === 'signin' && message.endpoint) { + await tryAuthenticateEndpoint(message.endpoint) + break + } if (message.authKind === 'signout') { await showSignOutMenu() break @@ -493,13 +497,13 @@ export class ChatController implements vscode.Disposable, vscode.WebviewViewProv const sidebarViewOnly = this.extensionClient.capabilities?.webviewNativeConfig?.view === 'single' const isEditorViewType = this.webviewPanelOrView?.viewType === 'cody.editorPanel' const webviewType = isEditorViewType && !sidebarViewOnly ? 'editor' : 'sidebar' - const endpointHistory = localStorage.getEndpointHistory() + const endpoints = localStorage.getEndpointHistory() ?? [] const uiKindIsWeb = (cenv.CODY_OVERRIDE_UI_KIND ?? vscode.env.uiKind) === vscode.UIKind.Web return { uiKindIsWeb, serverEndpoint: auth.serverEndpoint, - endpointHistory, + endpointHistory: [...endpoints].reverse(), experimentalNoodle: configuration.experimentalNoodle, smartApply: this.isSmartApplyEnabled(), webviewType, diff --git a/vscode/webviews/AuthPage.tsx b/vscode/webviews/AuthPage.tsx index d812beb0d30..74e17c52751 100644 --- a/vscode/webviews/AuthPage.tsx +++ b/vscode/webviews/AuthPage.tsx @@ -12,6 +12,14 @@ import { GlobeIcon, LockKeyholeIcon } from 'lucide-react' import { useCallback, useState } from 'react' import { Button } from './components/shadcn/ui/button' import { Form, FormControl, FormField, FormLabel, FormMessage } from './components/shadcn/ui/form' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from './components/shadcn/ui/select' import { useTelemetryRecorder } from './utils/telemetry' import { useConfig } from './utils/useConfig' @@ -23,6 +31,7 @@ export const AuthPage: React.FunctionComponent uiKindIsWeb, vscodeAPI, codyIDE, + endpointHistory, }) => { const authStatus = useConfig().authStatus const telemetryRecorder = useTelemetryRecorder() @@ -90,17 +99,29 @@ export const AuthPage: React.FunctionComponent

Cody Enterprise

- {isCodyWebUI || codyIDE === CodyIDE.VSCode ? ( -
+
+ {isNonVSCodeIDE ? ( + + ) : ( -
- ) : ( - - )} + )} +

Learn more about Sourcegraph Enterprise.

+ {endpointHistory?.length && ( +
+

Account History

+
+ +
+
+ )}
+ {endpointHistory.length && ( +
+ +
+ )} {actions.map(a => ( - )} - -

- Learn more about Sourcegraph Enterprise. -

- {endpoints?.length && (

Account History

@@ -164,6 +146,7 @@ interface LoginProps { vscodeAPI: VSCodeWrapper codyIDE: CodyIDE endpoints: string[] + authStatus: AuthStatus } const WebLogin: React.FunctionComponent< @@ -258,6 +241,14 @@ const ClientSignInForm: React.FC = ({ className, authStat } }, [formData.accessToken, onAccessTokenSignInClick, onBrowserSignInClick]) + const serverInvalid = + authStatus && + !authStatus.authenticated && + !authStatus.pendingValidation && + (authStatus.showNetworkError || authStatus.showInvalidAccessTokenError) + const showNetworkError = serverInvalid && authStatus.showNetworkError + const invalidToken = (serverInvalid && authStatus.showInvalidAccessTokenError) || false + return (
@@ -277,10 +268,7 @@ const ClientSignInForm: React.FC = ({ className, authStat Sign In with Browser - + = ({ className, authStat autoComplete="current-password" required /> - !isSourcegraphToken(formData.accessToken)}> + !isSourcegraphToken(formData.accessToken)} + forceMatch={invalidToken} + > Invalid access token. + {showNetworkError && ( + Network error. Please check your connection and try again. + )} Access token is required.