From acc7a22ba4ca5fea3f8627c514fe7b567eff8f39 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 12:41:43 +0300 Subject: [PATCH 01/18] remove integrations banners --- client/web/src/IdeExtensionTracker.tsx | 20 +-- client/web/src/hooks/index.ts | 1 - .../src/hooks/usePersistentCadence.test.ts | 53 ------ client/web/src/hooks/usePersistentCadence.ts | 42 ----- .../web/src/integration/blob-viewer.test.ts | 91 ----------- client/web/src/repo/RepoContainer.tsx | 49 +----- client/web/src/repo/RepoRevisionContainer.tsx | 7 +- .../web/src/repo/RepositoryFileTreePage.tsx | 14 +- .../actions/BrowserExtensionAlert.story.tsx | 23 --- .../repo/actions/BrowserExtensionAlert.tsx | 71 -------- .../repo/actions/GoToCodeHostAction.story.tsx | 30 ---- .../src/repo/actions/GoToCodeHostAction.tsx | 139 +--------------- .../actions/IdeExtensionAlert.module.scss | 9 - .../repo/actions/IdeExtensionAlert.story.tsx | 23 --- .../src/repo/actions/IdeExtensionAlert.tsx | 51 ------ ...InstallBrowserExtensionPopover.module.scss | 19 --- .../InstallBrowserExtensionPopover.tsx | 102 ------------ .../repo/actions/InstallIntegrationsAlert.tsx | 132 --------------- .../actions/NativeIntegrationAlert.story.tsx | 59 ------- .../repo/actions/NativeIntegrationAlert.tsx | 71 -------- client/web/src/routes.tsx | 2 - .../search/results/StreamingSearchResults.tsx | 154 ++---------------- .../src/tracking/BrowserExtensionTracker.tsx | 73 +-------- .../tracking/BrowserExtentionTracker.test.tsx | 39 +---- 24 files changed, 35 insertions(+), 1239 deletions(-) delete mode 100644 client/web/src/hooks/usePersistentCadence.test.ts delete mode 100644 client/web/src/hooks/usePersistentCadence.ts delete mode 100644 client/web/src/repo/actions/BrowserExtensionAlert.story.tsx delete mode 100644 client/web/src/repo/actions/BrowserExtensionAlert.tsx delete mode 100644 client/web/src/repo/actions/IdeExtensionAlert.module.scss delete mode 100644 client/web/src/repo/actions/IdeExtensionAlert.story.tsx delete mode 100644 client/web/src/repo/actions/IdeExtensionAlert.tsx delete mode 100644 client/web/src/repo/actions/InstallBrowserExtensionPopover.module.scss delete mode 100644 client/web/src/repo/actions/InstallBrowserExtensionPopover.tsx delete mode 100644 client/web/src/repo/actions/InstallIntegrationsAlert.tsx delete mode 100644 client/web/src/repo/actions/NativeIntegrationAlert.story.tsx delete mode 100644 client/web/src/repo/actions/NativeIntegrationAlert.tsx diff --git a/client/web/src/IdeExtensionTracker.tsx b/client/web/src/IdeExtensionTracker.tsx index 861864ae85838..2f2fc3860d84d 100644 --- a/client/web/src/IdeExtensionTracker.tsx +++ b/client/web/src/IdeExtensionTracker.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect } from 'react' import { useLocation } from 'react-router' @@ -35,21 +35,3 @@ export const IdeExtensionTracker: React.FunctionComponent { - const [lastVSCodeDetection] = useTemporarySetting('integrations.vscode.lastDetectionTimestamp', 0) - const [lastJetBrainsDetection] = useTemporarySetting('integrations.jetbrains.lastDetectionTimestamp', 0) - const [now] = useState(Date.now()) - - if (lastVSCodeDetection === undefined || lastJetBrainsDetection === undefined) { - return undefined - } - - if (now - lastVSCodeDetection < ONE_MONTH) { - return true - } - if (now - lastJetBrainsDetection < ONE_MONTH) { - return true - } - return false -} diff --git a/client/web/src/hooks/index.ts b/client/web/src/hooks/index.ts index e35af4d9e55f5..e724b310d58c8 100644 --- a/client/web/src/hooks/index.ts +++ b/client/web/src/hooks/index.ts @@ -1,3 +1,2 @@ export { useRoutesMatch } from './useRoutesMatch' -export { usePersistentCadence } from './usePersistentCadence' export { useHandleSubmitFeedback } from './useHandleSubmitFeedback' diff --git a/client/web/src/hooks/usePersistentCadence.test.ts b/client/web/src/hooks/usePersistentCadence.test.ts deleted file mode 100644 index cdeb4e32c32ab..0000000000000 --- a/client/web/src/hooks/usePersistentCadence.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { usePersistentCadence, reset } from './usePersistentCadence' - -const testKey = 'test' -const testKey2 = 'test2' -const testCadence = 5 - -beforeEach(() => { - localStorage.clear() - reset() -}) - -describe('usePersistentCadence', () => { - it('returns true on first run', () => { - expect(usePersistentCadence(testKey, testCadence)).toBe(true) - }) - - it('returns true on second run in the same session', () => { - usePersistentCadence(testKey, testCadence) - - expect(usePersistentCadence(testKey, testCadence)).toBe(true) - }) - - it('returns true on Nth run', () => { - localStorage.setItem(testKey, testCadence.toString()) - - expect(usePersistentCadence(testKey, testCadence)).toBe(true) - }) - - it('returns true on 2Nth run', () => { - localStorage.setItem(testKey, (2 * testCadence).toString()) - - expect(usePersistentCadence(testKey, testCadence)).toBe(true) - }) - - it('returns false on (2N+1)th run', () => { - localStorage.setItem(testKey, (2 * testCadence + 1).toString()) - - expect(usePersistentCadence(testKey, testCadence)).toBe(false) - }) - - it('handles different keys separately', () => { - localStorage.setItem(testKey, (2 * testCadence + 1).toString()) - - expect(usePersistentCadence(testKey2, testCadence)).toBe(true) - }) - - it('returns true on {N+shift}th run', () => { - const testShift = 2 - localStorage.setItem(testKey, (testCadence + testShift).toString()) - - expect(usePersistentCadence(testKey, testCadence, testShift)).toBe(true) - }) -}) diff --git a/client/web/src/hooks/usePersistentCadence.ts b/client/web/src/hooks/usePersistentCadence.ts deleted file mode 100644 index 069a9ac99fc6f..0000000000000 --- a/client/web/src/hooks/usePersistentCadence.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { isChromatic } from '@sourcegraph/storybook' - -const incrementedLocalStorageKeys = new Map() - -/** - * Initializes a key in local storage with 0, then increments it at each new import of this module. - * If the function is called in the same instance of this module over and over again, it'll keep returning - * the same value (e.g. 0 after first initialization) - * This is useful for incrementing a counter at each hard page load, but not at soft (React-level) reloads. - * - * "Shift" shifts the index of the page view to allow for alternating triggers. - * E.g. if you have two uses of this hook, "A" with cadence = 4 and shift = 0, and "B" with cadence = 4 and shift = 2, you'll get this: - * - * > Page load # Triggered - * > 0 A - * > 1 - - * > 2 B - * > 3 - - * > 4 A - * > 5 - - * > ... ... - * - * It always returns `false` when running on Chromatic. - */ -export function usePersistentCadence(localStorageKey: string, cadence: number, shift: number = 0): boolean { - if (isChromatic()) { - return false - } - if (!incrementedLocalStorageKeys.has(localStorageKey)) { - const pageViewCount = parseInt(localStorage.getItem(localStorageKey) || '', 10) || 0 - localStorage.setItem(localStorageKey, (pageViewCount + 1).toString()) - incrementedLocalStorageKeys.set(localStorageKey, pageViewCount) - return pageViewCount % cadence === shift - } - - const pageViewCount = incrementedLocalStorageKeys.get(localStorageKey) || 0 - return pageViewCount % cadence === shift -} - -export function reset(): void { - incrementedLocalStorageKeys.clear() -} diff --git a/client/web/src/integration/blob-viewer.test.ts b/client/web/src/integration/blob-viewer.test.ts index c22c4667e54af..8a2df2eb1b4ca 100644 --- a/client/web/src/integration/blob-viewer.test.ts +++ b/client/web/src/integration/blob-viewer.test.ts @@ -1,6 +1,5 @@ import assert from 'assert' -import { Page } from 'puppeteer' import type * as sourcegraph from 'sourcegraph' import { SharedGraphQlOperations } from '@sourcegraph/shared/src/graphql-operations' @@ -1081,95 +1080,5 @@ describe('Blob viewer', () => { throw new Error('Expected to navigate to file after clicking on link in references panel') } }) - - describe('browser extension discoverability', () => { - const HOVER_THRESHOLD = 5 - const HOVER_COUNT_KEY = 'hover-count' - - it.skip(`shows a popover about the browser extension when the user has seen ${HOVER_THRESHOLD} hovers and clicks "View on [code host]" button`, async () => { - testContext.server.get('https://github.com/*').intercept((request, response) => { - response.sendStatus(200) - }) - - await driver.page.goto(`${driver.sourcegraphBaseUrl}/github.com/sourcegraph/test/-/blob/test.ts`) - await driver.page.evaluate(() => localStorage.removeItem('hover-count')) - await driver.page.reload() - - await driver.page.waitForSelector('.test-go-to-code-host', { visible: true }) - // Close new tab after clicking link - const newPage = new Promise(resolve => - driver.browser.once('targetcreated', target => resolve(target.page())) - ) - await driver.page.click('.test-go-to-code-host', { button: 'middle' }) - await (await newPage).close() - - assert( - !(await driver.page.$('.test-install-browser-extension-popover')), - 'Expected popover to not be displayed before user reaches hover threshold' - ) - - // Hover over 'console' and 'log' 5 times combined - await driver.page.waitForSelector('.test-log-token', { visible: true }) - for (let index = 0; index < HOVER_THRESHOLD; index++) { - await driver.page.hover(index % 2 === 0 ? '.test-log-token' : '.test-console-token') - await driver.page.waitForSelector('[data-testid="hover-overlay"]', { visible: true }) - } - - await driver.page.click('.test-go-to-code-host', { button: 'middle' }) - await driver.page.waitForSelector('.test-install-browser-extension-popover', { visible: true }) - assert( - !!(await driver.page.$('.test-install-browser-extension-popover')), - 'Expected popover to be displayed after user reaches hover threshold' - ) - - const popoverHeader = await driver.page.evaluate( - () => document.querySelector('.test-install-browser-extension-popover-header')?.textContent - ) - assert.strictEqual( - popoverHeader, - "Take Sourcegraph's code intelligence to GitHub!", - 'Expected popover header text to reflect code host' - ) - }) - - it.skip(`shows an alert about the browser extension when the user has seen ${HOVER_THRESHOLD} hovers`, async () => { - await driver.page.goto(`${driver.sourcegraphBaseUrl}/github.com/sourcegraph/test/-/blob/test.ts`) - await driver.page.evaluate(HOVER_COUNT_KEY => localStorage.removeItem(HOVER_COUNT_KEY), HOVER_COUNT_KEY) - await driver.page.reload() - - // Alert should not be visible before the user reaches the hover threshold - assert( - !(await driver.page.$('[data-testid="install-browser-extension-alert"]')), - 'Expected "Install browser extension" alert to not be displayed before user reaches hover threshold' - ) - - // Hover over 'console' and 'log' $HOVER_THRESHOLD times combined - await driver.page.waitForSelector('.test-log-token', { visible: true }) - for (let index = 0; index < HOVER_THRESHOLD; index++) { - await driver.page.hover(index % 2 === 0 ? '.test-log-token' : '.test-console-token') - await driver.page.waitForSelector('[data-testid="hover-overlay"]', { visible: true }) - } - await driver.page.reload() - - // Alert should be visible now that the user has seen $HOVER_THRESHOLD hovers - await driver.page.waitForSelector('[data-testid="install-browser-extension-alert"]', { timeout: 5000 }) - - // Dismiss alert - await driver.page.click('.test-close-alert') - await driver.page.reload() - - // Alert should not show up now that the user has dismissed it once - await driver.page.waitForSelector('[data-testid="repo-header"]') - // `useIsBrowserExtensionActiveUser` emits false after 1000ms, so - // wait 500ms after [data-testid="repo-header"] is visible, at which point we know - // that `RepoContainer` has subscribed to `useIsBrowserExtensionActiveUser`. - // After this point, we know whether or not the alert will be displayed for this page load. - await driver.page.waitFor(1000) - assert( - !(await driver.page.$('[data-testid="install-browser-extension-alert"]')), - 'Expected "Install browser extension" alert to not be displayed before user dismisses it once' - ) - }) - }) }) }) diff --git a/client/web/src/repo/RepoContainer.tsx b/client/web/src/repo/RepoContainer.tsx index 1688df903ed1d..3f385a208bfe7 100644 --- a/client/web/src/repo/RepoContainer.tsx +++ b/client/web/src/repo/RepoContainer.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { mdiSourceRepository, mdiChevronDown } from '@mdi/js' import classNames from 'classnames' @@ -33,7 +33,6 @@ import { Icon, Button, ButtonGroup, - useLocalStorage, useObservable, Link, Popover, @@ -53,12 +52,10 @@ import { ExternalLinkFields, RepositoryFields } from '../graphql-operations' import { CodeInsightsProps } from '../insights/types' import { searchQueryForRepoRevision, SearchStreamingProps } from '../search' import { useNavbarQueryState } from '../stores' -import { useIsBrowserExtensionActiveUser } from '../tracking/BrowserExtensionTracker' import { RouteDescriptor } from '../util/contributions' import { parseBrowserRepoURL } from '../util/url' import { GoToCodeHostAction } from './actions/GoToCodeHostAction' -import type { ExtensionAlertProps } from './actions/InstallIntegrationsAlert' import { fetchFileExternalLinks, fetchRepository, resolveRevision } from './backend' import { RepoHeader, RepoHeaderActionButton, RepoHeaderContributionsLifecycleProps } from './RepoHeader' import { RepoHeaderContributionPortal } from './RepoHeaderContributionPortal' @@ -91,8 +88,7 @@ export interface RepoContainerContext Pick, CodeIntelligenceProps, BatchChangesProps, - CodeInsightsProps, - ExtensionAlertProps { + CodeInsightsProps { repo: RepositoryFields authenticatedUser: AuthenticatedUser | null repoSettingsAreaRoutes: readonly RepoSettingsAreaRoute[] @@ -125,7 +121,6 @@ interface RepoContainerProps ExtensionsControllerProps, ActivationProps, ThemeProps, - ExtensionAlertProps, Pick, BreadcrumbSetters, BreadcrumbsProps, @@ -146,10 +141,6 @@ interface RepoContainerProps isSourcegraphDotCom: boolean } -export const HOVER_COUNT_KEY = 'hover-count' - -export const HOVER_THRESHOLD = 5 - export interface HoverThresholdProps { /** * Called when a hover with content is shown. @@ -324,39 +315,6 @@ export const RepoContainer: React.FunctionComponent= HOVER_THRESHOLD - - // Increment hovers that the user has seen. Enable browser extension discoverability - // features after hover count threshold is reached (e.g. alerts, popovers) - // Store hover count in ref to avoid circular dependency - // hoverCount -> onHoverShown -> WebHoverOverlay (onHoverShown in useEffect deps) -> onHoverShown() - const hoverCountReference = useRef(hoverCount) - hoverCountReference.current = hoverCount - const onHoverShown = useCallback(() => { - const count = hoverCountReference.current + 1 - if (count > HOVER_THRESHOLD) { - // No need to keep updating localStorage - return - } - setHoverCount(count) - }, [setHoverCount]) - - const onPopoverDismissed = useCallback(() => { - setHasDismissedPopover(true) - }, []) - if (!repoOrError) { // Render nothing while loading return null @@ -393,7 +351,6 @@ export const RepoContainer: React.FunctionComponent diff --git a/client/web/src/repo/RepoRevisionContainer.tsx b/client/web/src/repo/RepoRevisionContainer.tsx index 04ba61e4b3a0c..03653abf6c55f 100644 --- a/client/web/src/repo/RepoRevisionContainer.tsx +++ b/client/web/src/repo/RepoRevisionContainer.tsx @@ -37,7 +37,6 @@ import { RouteDescriptor } from '../util/contributions' import { CopyPathAction } from './actions/CopyPathAction' import { GoToPermalinkAction } from './actions/GoToPermalinkAction' -import type { ExtensionAlertProps } from './actions/InstallIntegrationsAlert' import { ResolvedRevision } from './backend' import { RepoRevisionChevronDownIcon, RepoRevisionWrapper } from './components/RepoRevision' import { HoverThresholdProps, RepoContainerContext } from './RepoContainer' @@ -68,8 +67,7 @@ export interface RepoRevisionContainerContext SearchStreamingProps, Pick, BatchChangesProps, - CodeInsightsProps, - ExtensionAlertProps { + CodeInsightsProps { repo: RepositoryFields resolvedRev: ResolvedRevision @@ -104,8 +102,7 @@ interface RepoRevisionContainerProps Pick, CodeIntelligenceProps, BatchChangesProps, - CodeInsightsProps, - ExtensionAlertProps { + CodeInsightsProps { routes: readonly RepoRevisionContainerRoute[] repoSettingsAreaRoutes: readonly RepoSettingsAreaRoute[] repoSettingsSidebarGroups: readonly RepoSettingsSideBarGroup[] diff --git a/client/web/src/repo/RepositoryFileTreePage.tsx b/client/web/src/repo/RepositoryFileTreePage.tsx index 6869c3cf3c7ea..af29b5e6f9c22 100644 --- a/client/web/src/repo/RepositoryFileTreePage.tsx +++ b/client/web/src/repo/RepositoryFileTreePage.tsx @@ -2,7 +2,7 @@ import React from 'react' import { Redirect, RouteComponentProps } from 'react-router' -import { appendLineRangeQueryParameter, isErrorLike } from '@sourcegraph/common' +import { appendLineRangeQueryParameter } from '@sourcegraph/common' import { getModeFromPath } from '@sourcegraph/shared/src/languages' import { isLegacyFragment, parseQueryAndHash, toRepoURL } from '@sourcegraph/shared/src/util/url' @@ -11,7 +11,6 @@ import { ActionItemsBar } from '../extensions/components/ActionItemsBar' import { GettingStartedTour } from '../tour/GettingStartedTour' import { formatHash, formatLineOrPositionOrRange } from '../util/url' -import { InstallIntegrationsAlert } from './actions/InstallIntegrationsAlert' import { BlobPage } from './blob/BlobPage' import { BlobStatusBarContainer } from './blob/ui/BlobStatusBarContainer' import { RepoRevisionContainerContext } from './RepoRevisionContainer' @@ -89,11 +88,6 @@ export const RepositoryFileTreePage: React.FunctionComponent< globbing, } - const codeHostIntegrationMessaging: 'native-integration' | 'browser-extension' = - (!isErrorLike(context.settingsCascade.final) && - context.settingsCascade.final?.['alerts.codeHostIntegrationMessaging']) || - 'browser-extension' - return ( <> {objectType === 'blob' ? ( <> - {() => story()} - -const config: Meta = { - title: 'web/repo/actions', - decorators: [decorator], - parameters: { - component: BrowserExtensionAlert, - }, -} - -export default config - -export const BrowserExtensionAlertDefault: Story = () => ( - -) -BrowserExtensionAlertDefault.storyName = 'BrowserExtensionAlert' diff --git a/client/web/src/repo/actions/BrowserExtensionAlert.tsx b/client/web/src/repo/actions/BrowserExtensionAlert.tsx deleted file mode 100644 index 3fa9940a66f19..0000000000000 --- a/client/web/src/repo/actions/BrowserExtensionAlert.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useCallback, useEffect, useMemo } from 'react' - -import { getBrowserName } from '@sourcegraph/common' -import { CtaAlert } from '@sourcegraph/shared/src/components/CtaAlert' - -import { ExtensionRadialGradientIcon } from '../../components/CtaIcons' -import { eventLogger } from '../../tracking/eventLogger' - -interface Props { - className?: string - page: 'search' | 'file' - onAlertDismissed: () => void -} - -const LEARN_MORE_URL = - 'https://docs.sourcegraph.com/integration/browser_extension?utm_campaign=search-results-cta&utm_medium=direct_traffic&utm_source=in-product&utm_term=null&utm_content=install-browser-exten' - -const BROWSER_NAME = getBrowserName() -const BROWSER_NAME_TO_URL = { - chrome: 'https://chrome.google.com/webstore/detail/sourcegraph/dgjhfomjieaadpoljlnidmbgkdffpack', - firefox: 'https://addons.mozilla.org/en-US/firefox/addon/sourcegraph-for-firefox/', - safari: 'https://apps.apple.com/us/app/sourcegraph-for-safari/id1543262193', - other: LEARN_MORE_URL, -} - -export const BrowserExtensionAlert: React.FunctionComponent> = ({ - className, - page, - onAlertDismissed, -}) => { - const args = useMemo(() => ({ page, browser: BROWSER_NAME }), [page]) - - useEffect(() => { - eventLogger.log('InstallBrowserExtensionCTAShown', args, args) - }, [args]) - - const onBrowserExtensionPrimaryClick = useCallback((): void => { - eventLogger.log('InstallBrowserExtensionCTAClicked', args, args) - }, [args]) - - const onBrowserExtensionSecondaryClick = useCallback((): void => { - eventLogger.log('InstallBrowserExtensionLearnClicked', args, args) - }, [args]) - - const cta = { - label: BROWSER_NAME !== 'other' ? 'Install now' : 'Learn more', - href: BROWSER_NAME_TO_URL[BROWSER_NAME], - onClick: BROWSER_NAME !== 'other' ? onBrowserExtensionPrimaryClick : onBrowserExtensionSecondaryClick, - } - - const secondary = - BROWSER_NAME !== 'other' - ? { - label: 'Learn more', - href: LEARN_MORE_URL, - onClick: onBrowserExtensionSecondaryClick, - } - : undefined - - return ( - } - className={className} - onClose={onAlertDismissed} - /> - ) -} diff --git a/client/web/src/repo/actions/GoToCodeHostAction.story.tsx b/client/web/src/repo/actions/GoToCodeHostAction.story.tsx index c6b640ad9c3e7..68b5e45715be4 100644 --- a/client/web/src/repo/actions/GoToCodeHostAction.story.tsx +++ b/client/web/src/repo/actions/GoToCodeHostAction.story.tsx @@ -11,8 +11,6 @@ import { Button, Popover, PopoverTrigger, Icon } from '@sourcegraph/wildcard' import { WebStory } from '../../components/WebStory' -import { InstallBrowserExtensionPopover } from './InstallBrowserExtensionPopover' - const onClose = action('onClose') const onReject = action('onReject') const onInstall = action('onInstall') @@ -42,13 +40,6 @@ export const GitHub: Story = () => ( - ) }} @@ -72,13 +63,6 @@ export const GitLab: Story = () => ( - ) }} @@ -106,13 +90,6 @@ export const Phabricator: Story = () => ( - ) }} @@ -139,13 +116,6 @@ export const BitbucketServer: Story = () => ( - ) }} diff --git a/client/web/src/repo/actions/GoToCodeHostAction.tsx b/client/web/src/repo/actions/GoToCodeHostAction.tsx index 040e562fa8766..43ac1b4685e97 100644 --- a/client/web/src/repo/actions/GoToCodeHostAction.tsx +++ b/client/web/src/repo/actions/GoToCodeHostAction.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo, useState } from 'react' +import React, { useCallback, useMemo } from 'react' import { upperFirst, toLower } from 'lodash' import BitbucketIcon from 'mdi-react/BitbucketIcon' @@ -12,16 +12,7 @@ import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common' import { Position, Range } from '@sourcegraph/extension-api-types' import { PhabricatorIcon } from '@sourcegraph/shared/src/components/icons' // TODO: Switch mdi icon import { RevisionSpec, FileSpec } from '@sourcegraph/shared/src/util/url' -import { - useObservable, - useLocalStorage, - Popover, - PopoverTrigger, - PopoverTail, - PopoverOpenEvent, - Icon, - Tooltip, -} from '@sourcegraph/wildcard' +import { useObservable, Icon, Tooltip } from '@sourcegraph/wildcard' import { ExternalLinkFields, RepositoryFields, ExternalServiceKind } from '../../graphql-operations' import { eventLogger } from '../../tracking/eventLogger' @@ -29,22 +20,7 @@ import { fetchFileExternalLinks } from '../backend' import { RepoHeaderActionAnchor, RepoHeaderActionAnchorProps } from '../components/RepoHeaderActions' import { RepoHeaderContext } from '../RepoHeader' -import { InstallBrowserExtensionPopover } from './InstallBrowserExtensionPopover' - -interface GoToCodeHostPopoverProps { - /** - * Whether the GoToCodeHostAction can show a popover to install the browser extension. - * It may still not do so if the popover was permanently dismissed. - */ - canShowPopover: boolean - - /** - * Called when the popover is dismissed in any way ("No thanks", "Remind me later" or "Install"). - */ - onPopoverDismissed: () => void -} - -interface Props extends RevisionSpec, Partial, GoToCodeHostPopoverProps { +interface Props extends RevisionSpec, Partial { repo?: Pick | null filePath?: string commitRange?: string @@ -58,34 +34,13 @@ interface Props extends RevisionSpec, Partial, GoToCodeHostPopoverProp actionType?: 'nav' | 'dropdown' } -const HAS_PERMANENTLY_DISMISSED_POPUP_KEY = 'has-dismissed-browser-ext-popup' - /** * A repository header action that goes to the corresponding URL on an external code host. */ export const GoToCodeHostAction: React.FunctionComponent< React.PropsWithChildren > = props => { - const [isPopoverOpen, setIsPopoverOpen] = useState(false) - - const showPopover = useCallback(() => { - eventLogger.log('BrowserExtensionPopupOpened') - setIsPopoverOpen(true) - }, []) - - const closePopover = useCallback(() => { - setIsPopoverOpen(false) - }, []) - - const { onPopoverDismissed, repo, revision, filePath } = props - - const [hasPermanentlyDismissedPopup, setHasPermanentlyDismissedPopup] = useLocalStorage( - HAS_PERMANENTLY_DISMISSED_POPUP_KEY, - false - ) - - // Popover won't work with dropdown - const hijackLink = !hasPermanentlyDismissedPopup && props.canShowPopover && props.actionType !== 'dropdown' + const { repo, revision, filePath } = props /** * The external links for the current file/dir, or undefined while loading, null while not @@ -105,67 +60,7 @@ export const GoToCodeHostAction: React.FunctionComponent< }, [repo, revision, filePath]) ) - /** This is a hard rejection. Never ask the user again. */ - const onReject = useCallback(() => { - setHasPermanentlyDismissedPopup(true) - closePopover() - onPopoverDismissed() - - eventLogger.log('BrowserExtensionPopupRejected') - }, [closePopover, onPopoverDismissed, setHasPermanentlyDismissedPopup]) - - /** This is a soft rejection. Called when user clicks 'Remind me later', ESC, or outside of the modal body */ - const onClose = useCallback(() => { - onPopoverDismissed() - closePopover() - - eventLogger.log('BrowserExtensionPopupClosed') - }, [closePopover, onPopoverDismissed]) - - /** The user is likely to install the browser extension at this point, so don't show it again. */ - const onInstall = useCallback(() => { - setHasPermanentlyDismissedPopup(true) - closePopover() - onPopoverDismissed() - - eventLogger.log('BrowserExtensionPopupClickedInstall') - }, [closePopover, onPopoverDismissed, setHasPermanentlyDismissedPopup]) - - const onToggle = useCallback( - (event: PopoverOpenEvent) => { - if (event.isOpen === isPopoverOpen) { - return - } - - if (isPopoverOpen) { - closePopover() - return - } - - if (hijackLink) { - showPopover() - } - }, - [closePopover, hijackLink, isPopoverOpen, showPopover] - ) - - const onClick = useCallback( - (event: React.MouseEvent) => { - eventLogger.log('GoToCodeHostClicked') - - if (isPopoverOpen) { - event.preventDefault() - closePopover() - return - } - - if (hijackLink) { - event.preventDefault() - showPopover() - } - }, - [hijackLink, isPopoverOpen, showPopover, closePopover] - ) + const onClick = useCallback(() => eventLogger.log('GoToCodeHostClicked'), []) // If the default branch is undefined, set to HEAD const defaultBranch = @@ -235,7 +130,7 @@ export const GoToCodeHostAction: React.FunctionComponent< = { - to: hijackLink ? '' : url, + to: url, target: '_blank', rel: 'noopener noreferrer', id: TARGET_ID, @@ -260,26 +155,6 @@ export const GoToCodeHostAction: React.FunctionComponent< 'aria-label': descriptiveText, } - if (hijackLink) { - return ( - - - - - - - - - - ) - } - return ( diff --git a/client/web/src/repo/actions/IdeExtensionAlert.module.scss b/client/web/src/repo/actions/IdeExtensionAlert.module.scss deleted file mode 100644 index 12b19ce2575de..0000000000000 --- a/client/web/src/repo/actions/IdeExtensionAlert.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -.icons { - svg { - margin-right: 1rem; - } - - svg:last-child { - margin-right: 0; - } -} diff --git a/client/web/src/repo/actions/IdeExtensionAlert.story.tsx b/client/web/src/repo/actions/IdeExtensionAlert.story.tsx deleted file mode 100644 index b51bdb12c2a47..0000000000000 --- a/client/web/src/repo/actions/IdeExtensionAlert.story.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { action } from '@storybook/addon-actions' -import { DecoratorFn, Meta, Story } from '@storybook/react' - -import { WebStory } from '../../components/WebStory' - -import { IDEExtensionAlert } from './IdeExtensionAlert' - -const decorator: DecoratorFn = story => {() => story()} - -const config: Meta = { - title: 'web/repo/actions', - decorators: [decorator], - parameters: { - component: IDEExtensionAlert, - }, -} - -export default config - -export const IDEExtensionAlertDefault: Story = () => ( - -) -IDEExtensionAlertDefault.storyName = 'IDEExtensionAlert' diff --git a/client/web/src/repo/actions/IdeExtensionAlert.tsx b/client/web/src/repo/actions/IdeExtensionAlert.tsx deleted file mode 100644 index 5806a188fcde5..0000000000000 --- a/client/web/src/repo/actions/IdeExtensionAlert.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useEffect, useMemo, useCallback } from 'react' - -import { CtaAlert } from '@sourcegraph/shared/src/components/CtaAlert' - -import { AtomIcon, JetBrainsIcon, SublimeTextIcon, VSCodeIcon } from '../../components/CtaIcons' -import { eventLogger } from '../../tracking/eventLogger' - -import styles from './IdeExtensionAlert.module.scss' - -interface Props { - className?: string - page: 'search' | 'file' - onAlertDismissed: () => void -} - -export const IDEExtensionAlert: React.FunctionComponent> = ({ - className, - page, - onAlertDismissed, -}) => { - const args = useMemo(() => ({ page }), [page]) - useEffect(() => { - eventLogger.log('InstallIDEExtensionCTAShown', args, args) - }, [args]) - - const onIDEExtensionClick = useCallback((): void => { - eventLogger.log('InstallIDEExtensionCTAClicked', args, args) - }, [args]) - return ( - - - - - - - } - className={className} - onClose={onAlertDismissed} - /> - ) -} diff --git a/client/web/src/repo/actions/InstallBrowserExtensionPopover.module.scss b/client/web/src/repo/actions/InstallBrowserExtensionPopover.module.scss deleted file mode 100644 index 923cee8ca4a9c..0000000000000 --- a/client/web/src/repo/actions/InstallBrowserExtensionPopover.module.scss +++ /dev/null @@ -1,19 +0,0 @@ -.install-browser-extension-popover { - width: 31rem; -} - -.graphic-container { - margin-bottom: 2rem; - width: 11.25rem; -} - -.plus-icon { - color: var(--gray-06); - height: 1.25rem; - width: 1.25rem; -} - -.logo { - height: 3.5rem; - width: 3.5rem; -} diff --git a/client/web/src/repo/actions/InstallBrowserExtensionPopover.tsx b/client/web/src/repo/actions/InstallBrowserExtensionPopover.tsx deleted file mode 100644 index 755b19faa2f91..0000000000000 --- a/client/web/src/repo/actions/InstallBrowserExtensionPopover.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React from 'react' - -import classNames from 'classnames' -import ExportIcon from 'mdi-react/ExportIcon' -import PlusThickIcon from 'mdi-react/PlusThickIcon' - -import { ExternalServiceKind } from '@sourcegraph/shared/src/schema' -import { ButtonLink, PopoverContent, Position, H3, Text } from '@sourcegraph/wildcard' - -import { SourcegraphIcon } from '../../auth/icons' - -import { serviceKindDisplayNameAndIcon } from './GoToCodeHostAction' - -import styles from './InstallBrowserExtensionPopover.module.scss' - -interface Props { - url: string - serviceKind: ExternalServiceKind | null - onClose: () => void - onReject: () => void - onInstall: () => void -} - -export const InstallBrowserExtensionPopover: React.FunctionComponent> = ({ - url, - serviceKind, - onClose, - onReject, - onInstall, -}) => { - const { displayName, icon } = serviceKindDisplayNameAndIcon(serviceKind) - const Icon = icon || ExportIcon - - // Open all external links in new tab - const linkProps = { rel: 'noopener noreferrer', target: '_blank' } - - return ( - -
-

- Take Sourcegraph's code intelligence to {displayName}! -

- - Install Sourcegraph browser extension to add code intelligence{' '} - {serviceKind === ExternalServiceKind.PHABRICATOR - ? 'while browsing and reviewing code' - : `to ${serviceKind === ExternalServiceKind.GITLAB ? 'MR' : 'PR'}s and file views`}{' '} - on {displayName} or any other connected code host. - - -
- - - -
- -
- - No, thanks - - - - Remind me later - - - - Install browser extension - -
-
-
- ) -} diff --git a/client/web/src/repo/actions/InstallIntegrationsAlert.tsx b/client/web/src/repo/actions/InstallIntegrationsAlert.tsx deleted file mode 100644 index f7bfb0de94434..0000000000000 --- a/client/web/src/repo/actions/InstallIntegrationsAlert.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, { useCallback, useMemo } from 'react' - -import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting' -import { useLocalStorage } from '@sourcegraph/wildcard' - -import { usePersistentCadence } from '../../hooks' -import { useIsActiveIdeIntegrationUser } from '../../IdeExtensionTracker' -import { useTourQueryParameters } from '../../tour/components/Tour/TourAgent' -import { useIsBrowserExtensionActiveUser } from '../../tracking/BrowserExtensionTracker' -import { HOVER_COUNT_KEY, HOVER_THRESHOLD } from '../RepoContainer' - -import { BrowserExtensionAlert } from './BrowserExtensionAlert' -import { IDEExtensionAlert } from './IdeExtensionAlert' -import { NativeIntegrationAlert, NativeIntegrationAlertProps } from './NativeIntegrationAlert' - -export interface ExtensionAlertProps { - onExtensionAlertDismissed: () => void -} - -interface InstallIntegrationsAlertProps - extends Pick, - ExtensionAlertProps { - codeHostIntegrationMessaging: 'native-integration' | 'browser-extension' -} - -const CADENCE_KEY = 'InstallIntegrationsAlert.pageViews' -const DISPLAY_CADENCE = 6 -const IDE_CTA_CADENCE_SHIFT = 3 - -type CtaToDisplay = 'browser' | 'ide' - -export const InstallIntegrationsAlert: React.FunctionComponent< - React.PropsWithChildren -> = ({ codeHostIntegrationMessaging, externalURLs, className, page, onExtensionAlertDismissed }) => { - const displayBrowserExtensionCTABasedOnCadence = usePersistentCadence(CADENCE_KEY, DISPLAY_CADENCE) - const displayIDEExtensionCTABasedOnCadence = usePersistentCadence( - CADENCE_KEY, - DISPLAY_CADENCE, - IDE_CTA_CADENCE_SHIFT - ) - const isBrowserExtensionActiveUser = useIsBrowserExtensionActiveUser() - const isUsingIdeIntegration = useIsActiveIdeIntegrationUser() - const [hoverCount] = useLocalStorage(HOVER_COUNT_KEY, 0) - const [hasDismissedBrowserExtensionAlert, setHasDismissedBrowserExtensionAlert] = useTemporarySetting( - 'cta.browserExtensionAlertDismissed', - false - ) - const [hasDismissedIDEExtensionAlert, setHasDismissedIDEExtensionAlert] = useTemporarySetting( - 'cta.ideExtensionAlertDismissed', - false - ) - - const tourQueryParameters = useTourQueryParameters() - - const ctaToDisplay = useMemo( - (): CtaToDisplay | undefined => { - if (tourQueryParameters.isTour) { - return - } - - if ( - isBrowserExtensionActiveUser === false && - displayBrowserExtensionCTABasedOnCadence && - hasDismissedBrowserExtensionAlert === false && - hoverCount >= HOVER_THRESHOLD - ) { - return 'browser' - } - - if ( - isUsingIdeIntegration === false && - displayIDEExtensionCTABasedOnCadence && - hasDismissedIDEExtensionAlert === false - ) { - return 'ide' - } - - return - }, - /** - * Intentionally use useMemo() here without a dependency on hoverCount to only show the alert on the next reload, - * to not cause an annoying layout shift from displaying the alert. - */ - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - displayBrowserExtensionCTABasedOnCadence, - displayIDEExtensionCTABasedOnCadence, - hasDismissedBrowserExtensionAlert, - hasDismissedIDEExtensionAlert, - isBrowserExtensionActiveUser, - isUsingIdeIntegration, - tourQueryParameters, - ] - ) - - const onAlertDismissed = useCallback(() => { - onExtensionAlertDismissed() - if (ctaToDisplay === 'browser') { - setHasDismissedBrowserExtensionAlert(true) - } - - if (ctaToDisplay === 'ide') { - setHasDismissedIDEExtensionAlert(true) - } - }, [ - ctaToDisplay, - onExtensionAlertDismissed, - setHasDismissedBrowserExtensionAlert, - setHasDismissedIDEExtensionAlert, - ]) - - if (ctaToDisplay === 'browser') { - if (codeHostIntegrationMessaging === 'native-integration') { - return ( - - ) - } - - return - } - - if (ctaToDisplay === 'ide') { - return - } - - return null -} diff --git a/client/web/src/repo/actions/NativeIntegrationAlert.story.tsx b/client/web/src/repo/actions/NativeIntegrationAlert.story.tsx deleted file mode 100644 index 540310a8c5396..0000000000000 --- a/client/web/src/repo/actions/NativeIntegrationAlert.story.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react' - -import { action } from '@storybook/addon-actions' -import { DecoratorFn, Meta, Story } from '@storybook/react' - -import { ExternalServiceKind } from '@sourcegraph/shared/src/schema' - -import { WebStory } from '../../components/WebStory' - -import { NativeIntegrationAlert } from './NativeIntegrationAlert' - -const onAlertDismissed = action('onAlertDismissed') - -const decorator: DecoratorFn = story => {() => story()} - -const config: Meta = { - title: 'web/repo/actions/NativeIntegrationAlert', - decorators: [decorator], - parameters: { - component: NativeIntegrationAlert, - // Disable Chromatic for the non-GitHub alerts since they are mostly the same - chromatic: { - disable: true, - }, - }, -} - -export default config - -const NativeIntegrationAlertWrapper: React.FunctionComponent< - React.PropsWithChildren<{ serviceKind: ExternalServiceKind }> -> = ({ serviceKind }) => ( - -) - -export const GitHub: Story = () => -GitHub.parameters = { - chromatic: { disable: false }, -} -GitHub.storyName = 'GitHub' - -export const GitLab: Story = () => -GitLab.storyName = 'GitLab' - -export const Phabricator: Story = () => - -export const BitbucketServer: Story = () => ( - -) -BitbucketServer.storyName = 'Bitbucket server' diff --git a/client/web/src/repo/actions/NativeIntegrationAlert.tsx b/client/web/src/repo/actions/NativeIntegrationAlert.tsx deleted file mode 100644 index 45bcb03f537f9..0000000000000 --- a/client/web/src/repo/actions/NativeIntegrationAlert.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useEffect, useCallback, useMemo } from 'react' - -import { CtaAlert } from '@sourcegraph/shared/src/components/CtaAlert' -import { AlertLink } from '@sourcegraph/wildcard' - -import { ExtensionRadialGradientIcon } from '../../components/CtaIcons' -import { ExternalLinkFields, ExternalServiceKind } from '../../graphql-operations' -import { eventLogger } from '../../tracking/eventLogger' - -import { serviceKindDisplayNameAndIcon } from './GoToCodeHostAction' - -export interface NativeIntegrationAlertProps { - className?: string - page: 'search' | 'file' - onAlertDismissed: () => void - externalURLs: ExternalLinkFields[] -} - -/** Code hosts the browser extension supports */ -const supportedServiceTypes = new Set([ - ExternalServiceKind.GITHUB, - ExternalServiceKind.GITLAB, - ExternalServiceKind.PHABRICATOR, - ExternalServiceKind.BITBUCKETSERVER, -]) - -export const NativeIntegrationAlert: React.FunctionComponent> = ({ - className, - page, - onAlertDismissed, - externalURLs, -}) => { - const args = useMemo(() => ({ page }), [page]) - useEffect(() => { - eventLogger.log('NativeIntegrationInstallShown', args, args) - }, [args]) - - const installLinkClickHandler = useCallback((): void => { - eventLogger.log('NativeIntegrationInstallClicked', args, args) - }, [args]) - - const externalLink = externalURLs.find(link => link.serviceKind && supportedServiceTypes.has(link.serviceKind)) - if (!externalLink) { - return null - } - - const { serviceKind } = externalLink - const { displayName } = serviceKindDisplayNameAndIcon(serviceKind) - - return ( - - Sourcegraph's code intelligence will follow you to your code host.{' '} - - Learn more - - - } - cta={{ label: 'Try it out', href: externalLink.url, onClick: installLinkClickHandler }} - icon={} - className={className} - onClose={onAlertDismissed} - /> - ) -} diff --git a/client/web/src/routes.tsx b/client/web/src/routes.tsx index fa211e92e2a40..0862101e9d68b 100644 --- a/client/web/src/routes.tsx +++ b/client/web/src/routes.tsx @@ -14,7 +14,6 @@ import { CreateNotebookPage } from './notebooks/createPage/CreateNotebookPage' import { NotebooksListPage } from './notebooks/listPage/NotebooksListPage' import { ConnectGitHubAppPage } from './org/settings/codeHosts/ConnectGitHubAppPage' import { InstallGitHubAppSuccessPage } from './org/settings/codeHosts/InstallGitHubAppSuccessPage' -import type { ExtensionAlertProps } from './repo/actions/InstallIntegrationsAlert' import { PageRoutes } from './routes.constants' import { SearchPageWrapper } from './search/SearchPageWrapper' import { getExperimentalFeatures, useExperimentalFeatures } from './stores' @@ -37,7 +36,6 @@ export interface LayoutRouteComponentProps Observable } -const CTA_ALERTS_CADENCE_KEY = 'SearchResultCtaAlerts.pageViews' -const CTA_ALERT_DISPLAY_CADENCE = 6 -const IDE_CTA_CADENCE_SHIFT = 3 - -type CtaToDisplay = 'signup' | 'browser' | 'ide' - -function useCtaAlert( - isAuthenticated: boolean, - areResultsFound: boolean -): { - ctaToDisplay?: CtaToDisplay - onCtaAlertDismissed: () => void -} { - const [hasDismissedSignupAlert, setHasDismissedSignupAlert] = useLocalStorage( - 'StreamingSearchResults.hasDismissedSignupAlert', - false - ) - const [hasDismissedBrowserExtensionAlert, setHasDismissedBrowserExtensionAlert] = useTemporarySetting( - 'cta.browserExtensionAlertDismissed', - false - ) - const [hasDismissedIDEExtensionAlert, setHasDismissedIDEExtensionAlert] = useTemporarySetting( - 'cta.ideExtensionAlertDismissed', - false - ) - const isBrowserExtensionActiveUser = useIsBrowserExtensionActiveUser() - const isUsingIdeIntegration = useIsActiveIdeIntegrationUser() - - const displaySignupAndBrowserExtensionCTAsBasedOnCadence = usePersistentCadence( - CTA_ALERTS_CADENCE_KEY, - CTA_ALERT_DISPLAY_CADENCE - ) - const displayIDEExtensionCTABasedOnCadence = usePersistentCadence( - CTA_ALERTS_CADENCE_KEY, - CTA_ALERT_DISPLAY_CADENCE, - IDE_CTA_CADENCE_SHIFT - ) - - const tourQueryParameters = useTourQueryParameters() - - const ctaToDisplay = useMemo((): CtaToDisplay | undefined => { - if (!areResultsFound) { - return - } - if (tourQueryParameters.isTour) { - return - } - - if (!hasDismissedSignupAlert && !isAuthenticated && displaySignupAndBrowserExtensionCTAsBasedOnCadence) { - return 'signup' - } - - if ( - hasDismissedBrowserExtensionAlert === false && - isAuthenticated && - isBrowserExtensionActiveUser === false && - displaySignupAndBrowserExtensionCTAsBasedOnCadence - ) { - return 'browser' - } - - if ( - isUsingIdeIntegration === false && - displayIDEExtensionCTABasedOnCadence && - hasDismissedIDEExtensionAlert === false - ) { - return 'ide' - } - - return - }, [ - areResultsFound, - tourQueryParameters?.isTour, - hasDismissedSignupAlert, - isAuthenticated, - displaySignupAndBrowserExtensionCTAsBasedOnCadence, - hasDismissedBrowserExtensionAlert, - isBrowserExtensionActiveUser, - isUsingIdeIntegration, - displayIDEExtensionCTABasedOnCadence, - hasDismissedIDEExtensionAlert, - ]) - - const onCtaAlertDismissed = useCallback((): void => { - if (ctaToDisplay === 'signup') { - setHasDismissedSignupAlert(true) - } else if (ctaToDisplay === 'browser') { - setHasDismissedBrowserExtensionAlert(true) - } else if (ctaToDisplay === 'ide') { - setHasDismissedIDEExtensionAlert(true) - } - }, [ - ctaToDisplay, - setHasDismissedBrowserExtensionAlert, - setHasDismissedIDEExtensionAlert, - setHasDismissedSignupAlert, - ]) - - return { - ctaToDisplay, - onCtaAlertDismissed, - } -} - export const StreamingSearchResults: React.FunctionComponent< React.PropsWithChildren > = props => { @@ -335,15 +223,18 @@ export const StreamingSearchResults: React.FunctionComponent< }, [telemetryService]) const resultsFound = useMemo(() => (results ? results.results.length > 0 : false), [results]) - const { ctaToDisplay, onCtaAlertDismissed } = useCtaAlert(!!authenticatedUser, resultsFound) - - // Log view event when signup CTA is shown - useEffect(() => { - if (ctaToDisplay === 'signup') { - telemetryService.log('SearchResultResultsCTAShown') - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ctaToDisplay]) + const submittedSearchesCount = getSubmittedSearchesCount() + const isValidSignUpCtaCadence = submittedSearchesCount < 5 || submittedSearchesCount % 5 === 0 + const showSignUpCta = !authenticatedUser && resultsFound && isValidSignUpCtaCadence + + // TODO: decide on the signup banner and uncomment/remove + // // Log view event when signup CTA is shown + // useEffect(() => { + // if (ctaToDisplay === 'signup') { + // telemetryService.log('SearchResultResultsCTAShown') + // } + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [ctaToDisplay]) return (
@@ -422,7 +313,7 @@ export const StreamingSearchResults: React.FunctionComponent<
)} - {ctaToDisplay === 'signup' && ( + {showSignUpCta && ( - )} - {ctaToDisplay === 'browser' && ( - - )} - {ctaToDisplay === 'ide' && ( - undefined || onCtaAlertDismissed} // TODO: decide on the signup banner and fix/remove /> )} + = merge( // If the marker exists, the extension is installed @@ -65,64 +58,6 @@ export const browserExtensionMessageReceived: Observable<{ platform?: string; ve refCount() ) -/** - * A better way to check if the Chrome extension is installed that doesn't depend on the extension having permissions to the page. - * This is not possible on Firefox though. - */ -const checkChromeExtensionInstalled = (): Observable => { - if (!IS_CHROME) { - return of(false) - } - return fromFetch(`chrome-extension://${CHROME_EXTENSION_ID}/img/icon-16.png`, { - selector: response => of(response.ok), - }).pipe(catchError(() => of(false))) -} - -function pipeIf(predicate: (v: T) => boolean, ...pipes: OperatorFunction[]) { - return function (source: Observable) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return source.pipe(mergeMap(value => (predicate(value) ? of(value).pipe(...pipes) : of(value)))) - } -} - -/** - * Returns whether code is running in jest unit tests or not - */ -const isUnitTestRunning = (): boolean => process.env.JEST_WORKER_ID !== undefined - -/** - * Indicates if the current user has the browser extension installed. It waits 1000ms for the browser - * extension to inject a DOM marker element, and if it doesn't, emits false - */ -const browserExtensionInstalled: Observable = concat( - checkChromeExtensionInstalled().pipe(filter(isInstalled => isInstalled)), - observeQuerySelector({ selector: EXTENSION_MARKER_ID, timeout: 1000 }).pipe( - mapTo(true), - catchError(() => [false]) - ) -).pipe( - take(1), - // Replay the same latest value for every subscriber unless running in tests - pipeIf(() => !isUnitTestRunning(), publishReplay(1), refCount()) -) - -/** - * Returns whether user has currently installed browser extension or have used it for the past week on this particular browser. - */ -export function useIsBrowserExtensionActiveUser(): boolean | undefined { - // NOTE: intentionally using localStorage to keep track per browser instead user settings across browsers - const [lastBrowserExtensionDetection] = useLocalStorage(BROWSER_EXTENSION_LAST_DETECTION_KEY, 0) - const isBrowserExtensionInstalled = useObservable(browserExtensionInstalled) - const [now] = useState(Date.now()) - - if (lastBrowserExtensionDetection && now - lastBrowserExtensionDetection < WEEK) { - return true - } - - return isBrowserExtensionInstalled -} - /** * This component uses extension marker DOM element or UTM parameters to detect incoming traffic from our browser extensions (Chrome, Safari, Firefox) * and updates a localStorage whenever these are found. @@ -158,3 +93,5 @@ export const BrowserExtensionTracker: React.FunctionComponent { jest.useFakeTimers() }) }) - -describe('useIsBrowserExtensionActiveUser', () => { - afterAll(hookCleanup) - - afterEach(() => { - localStorage.clear() - }) - - test('Returns falsy', async () => { - const { result, waitForNextUpdate } = renderHook(() => useIsBrowserExtensionActiveUser()) - expect(result.current).toBeUndefined() - await waitForNextUpdate() - expect(result.current).toBeFalsy() - }) - - test('Returns truthy if "localStorage" item exist', () => { - localStorage.setItem(BROWSER_EXTENSION_LAST_DETECTION_KEY, `${Date.now()}`) - const { result } = renderHook(() => useIsBrowserExtensionActiveUser()) - expect(result.current).toBeTruthy() - }) - - test('Returns truthy if extension marker DOM element exist', async () => { - jest.spyOn(document, 'querySelector').mockImplementation(selector => - selector === `#${BROWSER_EXTENSION_MARKER_ELEMENT}` ? (document.createElement('div') as Element) : null - ) - - const { result, waitForNextUpdate } = renderHook(() => useIsBrowserExtensionActiveUser()) - expect(result.current).toBeUndefined() - - await waitForNextUpdate() - - expect(result.current).toBeTruthy() - - jest.resetAllMocks() - }) -}) From 393a727287aae7c64466c7b6f61781f47d21c6fb Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 13:04:02 +0300 Subject: [PATCH 02/18] remove unused variable --- client/web/src/IdeExtensionTracker.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/web/src/IdeExtensionTracker.tsx b/client/web/src/IdeExtensionTracker.tsx index 2f2fc3860d84d..b575305a55dab 100644 --- a/client/web/src/IdeExtensionTracker.tsx +++ b/client/web/src/IdeExtensionTracker.tsx @@ -4,8 +4,6 @@ import { useLocation } from 'react-router' import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting' -const ONE_MONTH = 1000 * 60 * 60 * 24 * 30 - /** * This component uses UTM parameters to detect incoming traffic from our IDE extensions (VS Code * and JetBrains) and updates a temporary setting whenever these are found. From d7e5c4797013a1583c9d8da16bc5623a53ff3c95 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 16:28:29 +0300 Subject: [PATCH 03/18] remove unused icons --- client/web/src/components/CtaIcons.tsx | 93 -------------------------- 1 file changed, 93 deletions(-) diff --git a/client/web/src/components/CtaIcons.tsx b/client/web/src/components/CtaIcons.tsx index 10aa9d7687e52..8cf4f81f68405 100644 --- a/client/web/src/components/CtaIcons.tsx +++ b/client/web/src/components/CtaIcons.tsx @@ -171,96 +171,3 @@ export const VSCodeIcon = React.memo(({ width = 30, height = 30 }: { width?: num /> )) - -export const JetBrainsIcon = React.memo(({ width = 30, height = 30 }: { width?: number; height?: number } = {}) => ( - - - - - - - - -)) - -export const AtomIcon = React.memo(({ width = 30, height = 30 }: { width?: number; height?: number } = {}) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)) - -export const SublimeTextIcon = React.memo(({ width = 30, height = 30 }: { width?: number; height?: number } = {}) => ( - - - - - - - - - - - - -)) From 5013472be10279fd63bbbd1744bec964fa98cc63 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 16:30:57 +0300 Subject: [PATCH 04/18] remove unused icons --- client/web/src/components/CtaIcons.tsx | 46 -------------------------- 1 file changed, 46 deletions(-) diff --git a/client/web/src/components/CtaIcons.tsx b/client/web/src/components/CtaIcons.tsx index 8cf4f81f68405..e58d25d99d344 100644 --- a/client/web/src/components/CtaIcons.tsx +++ b/client/web/src/components/CtaIcons.tsx @@ -27,52 +27,6 @@ export const BookmarkRadialGradientIcon = React.memo(() => ( )) -export const ExtensionRadialGradientIcon = React.memo(() => ( - - - - - - - - - - - - - - - - - - - - -)) - export const SearchBetaIcon = React.memo(() => ( From 8f1ca36dd4568db02b54af76f6a7eabac87cdc82 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 16:32:42 +0300 Subject: [PATCH 05/18] replace unused icon in story --- client/shared/src/components/CtaAlert.story.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/shared/src/components/CtaAlert.story.tsx b/client/shared/src/components/CtaAlert.story.tsx index 344db761b1876..1499d5cc47daf 100644 --- a/client/shared/src/components/CtaAlert.story.tsx +++ b/client/shared/src/components/CtaAlert.story.tsx @@ -1,7 +1,7 @@ import { DecoratorFn, Meta, Story } from '@storybook/react' // eslint-disable-next-line no-restricted-imports -import { ExtensionRadialGradientIcon } from '@sourcegraph/web/src/components/CtaIcons' +import { BookmarkRadialGradientIcon } from '@sourcegraph/web/src/components/CtaIcons' // eslint-disable-next-line no-restricted-imports import { WebStory } from '@sourcegraph/web/src/components/WebStory' @@ -28,7 +28,7 @@ export const Default: Story = () => ( title="Title" description="Description" cta={{ label: 'Label', href: '#' }} - icon={} + icon={} onClose={() => {}} /> ) From 5f4a0092a68d0afda6a126d10a981fe81620d8e1 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Wed, 13 Jul 2022 19:14:44 +0300 Subject: [PATCH 06/18] remove signup CTA --- client/web/src/search/helpers.tsx | 7 ---- .../search/results/StreamingSearchResults.tsx | 32 +------------------ 2 files changed, 1 insertion(+), 38 deletions(-) diff --git a/client/web/src/search/helpers.tsx b/client/web/src/search/helpers.tsx index acd36ecc140a9..b4d61c9081cc5 100644 --- a/client/web/src/search/helpers.tsx +++ b/client/web/src/search/helpers.tsx @@ -7,12 +7,6 @@ import { buildSearchURLQuery } from '@sourcegraph/shared/src/util/url' import { eventLogger } from '../tracking/eventLogger' -const SUBMITTED_SEARCHES_COUNT_KEY = 'submitted-searches-count' - -export function getSubmittedSearchesCount(): number { - return parseInt(localStorage.getItem(SUBMITTED_SEARCHES_COUNT_KEY) || '0', 10) -} - /** * @param activation If set, records the DidSearch activation event for the new user activation * flow. @@ -54,7 +48,6 @@ export function submitSearch({ }, { source } ) - localStorage.setItem(SUBMITTED_SEARCHES_COUNT_KEY, JSON.stringify(getSubmittedSearchesCount() + 1)) history.push(path, { ...history.location.state, query }) if (activation) { activation.update({ DidSearch: true }) diff --git a/client/web/src/search/results/StreamingSearchResults.tsx b/client/web/src/search/results/StreamingSearchResults.tsx index d02c78ec40fdb..b519d29627ce3 100644 --- a/client/web/src/search/results/StreamingSearchResults.tsx +++ b/client/web/src/search/results/StreamingSearchResults.tsx @@ -13,7 +13,6 @@ import { FetchFileParameters, } from '@sourcegraph/search-ui' import { ActivationProps } from '@sourcegraph/shared/src/components/activation/Activation' -import { CtaAlert } from '@sourcegraph/shared/src/components/CtaAlert' import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller' import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations' import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context' @@ -23,11 +22,9 @@ import { LATEST_VERSION, StreamSearchOptions } from '@sourcegraph/shared/src/sea import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' import { ThemeProps } from '@sourcegraph/shared/src/theme' -import { buildGetStartedURL } from '@sourcegraph/shared/src/util/url' import { SearchStreamingProps } from '..' import { AuthenticatedUser } from '../../auth' -import { SearchBetaIcon } from '../../components/CtaIcons' import { PageTitle } from '../../components/PageTitle' import { CodeInsightsProps } from '../../insights/types' import { isCodeInsightsEnabled } from '../../insights/utils/is-code-insights-enabled' @@ -40,7 +37,7 @@ import { } from '../../stores' import { GettingStartedTour } from '../../tour/GettingStartedTour' import { SearchUserNeedsCodeHost } from '../../user/settings/codeHosts/OrgUserNeedsCodeHost' -import { getSubmittedSearchesCount, submitSearch } from '../helpers' +import { submitSearch } from '../helpers' import { DidYouMean } from '../suggestion/DidYouMean' import { LuckySearch } from '../suggestion/LuckySearch' @@ -223,18 +220,6 @@ export const StreamingSearchResults: React.FunctionComponent< }, [telemetryService]) const resultsFound = useMemo(() => (results ? results.results.length > 0 : false), [results]) - const submittedSearchesCount = getSubmittedSearchesCount() - const isValidSignUpCtaCadence = submittedSearchesCount < 5 || submittedSearchesCount % 5 === 0 - const showSignUpCta = !authenticatedUser && resultsFound && isValidSignUpCtaCadence - - // TODO: decide on the signup banner and uncomment/remove - // // Log view event when signup CTA is shown - // useEffect(() => { - // if (ctaToDisplay === 'signup') { - // telemetryService.log('SearchResultResultsCTAShown') - // } - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, [ctaToDisplay]) return (
@@ -313,21 +298,6 @@ export const StreamingSearchResults: React.FunctionComponent<
)} - {showSignUpCta && ( - } - className="mr-3 percy-display-none" - onClose={() => undefined || onCtaAlertDismissed} // TODO: decide on the signup banner and fix/remove - /> - )} Date: Wed, 13 Jul 2022 19:15:29 +0300 Subject: [PATCH 07/18] remove unused event handler --- client/web/src/search/results/StreamingSearchResults.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/web/src/search/results/StreamingSearchResults.tsx b/client/web/src/search/results/StreamingSearchResults.tsx index b519d29627ce3..7f2583b4e6b4b 100644 --- a/client/web/src/search/results/StreamingSearchResults.tsx +++ b/client/web/src/search/results/StreamingSearchResults.tsx @@ -214,11 +214,6 @@ export const StreamingSearchResults: React.FunctionComponent< ) const [showSidebar, setShowSidebar] = useState(false) - const onSignUpClick = useCallback((): void => { - const args = { page: 'search' } - telemetryService.log('SignUpPLGSearchCTA_1_Search', args, args) - }, [telemetryService]) - const resultsFound = useMemo(() => (results ? results.results.length > 0 : false), [results]) return ( From a128c48724060ab2b53e559c6de9ee543c2aef84 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 10:10:11 +0300 Subject: [PATCH 08/18] remove leftovers --- client/web/src/Layout.tsx | 11 +------ client/web/src/nav/UserNavItem.tsx | 30 +------------------ .../web/src/repo/RepositoryFileTreePage.tsx | 1 - .../repo/actions/GoToCodeHostAction.story.tsx | 5 ---- 4 files changed, 2 insertions(+), 45 deletions(-) diff --git a/client/web/src/Layout.tsx b/client/web/src/Layout.tsx index 193c9c9a7574a..743e1648cf50e 100644 --- a/client/web/src/Layout.tsx +++ b/client/web/src/Layout.tsx @@ -1,4 +1,4 @@ -import React, { Suspense, useCallback, useEffect, useMemo } from 'react' +import React, { Suspense, useEffect, useMemo } from 'react' import classNames from 'classnames' import { Redirect, Route, RouteComponentProps, Switch, matchPath } from 'react-router' @@ -42,7 +42,6 @@ import { GlobalAlerts } from './global/GlobalAlerts' import { GlobalDebug } from './global/GlobalDebug' import { SurveyToast } from './marketing/toast' import { GlobalNavbar } from './nav/GlobalNavbar' -import { useExtensionAlertAnimation } from './nav/UserNavItem' import { OrgAreaRoute } from './org/area/OrgArea' import { OrgAreaHeaderNavItem } from './org/area/OrgHeader' import { RepoContainerRoute } from './repo/RepoContainer' @@ -172,13 +171,6 @@ export const Layout: React.FunctionComponent { - startExtensionAlertAnimation() - }, [startExtensionAlertAnimation]) - useScrollToLocationHash(props.location) // Note: this was a poor UX and is disabled for now, see https://github.com/sourcegraph/sourcegraph/issues/30192 @@ -207,7 +199,6 @@ export const Layout: React.FunctionComponent void -} { - const [isAnimating, setIsAnimating] = useState(false) - - const animationManager = useTimeoutManager() - - const startExtensionAlertAnimation = useCallback(() => { - if (!isAnimating) { - setIsAnimating(true) - - animationManager.setTimeout(() => { - setIsAnimating(false) - }, 5100) - } - }, [isAnimating, animationManager]) - - return { isExtensionAlertAnimating: isAnimating, startExtensionAlertAnimation } -} - /** * Triggers Keyboard Shortcut help when the button is clicked in the Menu Nav item */ diff --git a/client/web/src/repo/RepositoryFileTreePage.tsx b/client/web/src/repo/RepositoryFileTreePage.tsx index af29b5e6f9c22..3cc1a15c74c1d 100644 --- a/client/web/src/repo/RepositoryFileTreePage.tsx +++ b/client/web/src/repo/RepositoryFileTreePage.tsx @@ -38,7 +38,6 @@ export const RepositoryFileTreePage: React.FunctionComponent< resolvedRev: { commitID, defaultBranch }, match, globbing, - onExtensionAlertDismissed, ...context } = props // The decoding depends on the pinned `history` version. diff --git a/client/web/src/repo/actions/GoToCodeHostAction.story.tsx b/client/web/src/repo/actions/GoToCodeHostAction.story.tsx index 68b5e45715be4..c8c9e94413c52 100644 --- a/client/web/src/repo/actions/GoToCodeHostAction.story.tsx +++ b/client/web/src/repo/actions/GoToCodeHostAction.story.tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from 'react' import { mdiGithub, mdiGitlab, mdiBitbucket } from '@mdi/js' -import { action } from '@storybook/addon-actions' import { Meta, Story, DecoratorFn } from '@storybook/react' import { PhabricatorIcon } from '@sourcegraph/shared/src/components/icons' @@ -11,10 +10,6 @@ import { Button, Popover, PopoverTrigger, Icon } from '@sourcegraph/wildcard' import { WebStory } from '../../components/WebStory' -const onClose = action('onClose') -const onReject = action('onReject') -const onInstall = action('onInstall') - const decorator: DecoratorFn = story =>
{story()}
const config: Meta = { From f58ed49bee5cc318e69bba7f2beb84ff1c2f114a Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 10:13:38 +0300 Subject: [PATCH 09/18] remove VSCE signup alert --- .../src/components/CtaAlert.module.scss | 9 --- .../shared/src/components/CtaAlert.story.tsx | 35 --------- client/shared/src/components/CtaAlert.tsx | 71 ------------------- .../search-panel/SearchResultsView.tsx | 18 ----- 4 files changed, 133 deletions(-) delete mode 100644 client/shared/src/components/CtaAlert.module.scss delete mode 100644 client/shared/src/components/CtaAlert.story.tsx delete mode 100644 client/shared/src/components/CtaAlert.tsx diff --git a/client/shared/src/components/CtaAlert.module.scss b/client/shared/src/components/CtaAlert.module.scss deleted file mode 100644 index ab33d384bddd5..0000000000000 --- a/client/shared/src/components/CtaAlert.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -.cta { - &-title { - font-size: 1rem; - } - - &-description { - font-size: 0.875rem; - } -} diff --git a/client/shared/src/components/CtaAlert.story.tsx b/client/shared/src/components/CtaAlert.story.tsx deleted file mode 100644 index 1499d5cc47daf..0000000000000 --- a/client/shared/src/components/CtaAlert.story.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { DecoratorFn, Meta, Story } from '@storybook/react' - -// eslint-disable-next-line no-restricted-imports -import { BookmarkRadialGradientIcon } from '@sourcegraph/web/src/components/CtaIcons' -// eslint-disable-next-line no-restricted-imports -import { WebStory } from '@sourcegraph/web/src/components/WebStory' - -import { CtaAlert } from './CtaAlert' - -const decorator: DecoratorFn = story => {() => story()} - -const config: Meta = { - title: 'shared', - decorators: [decorator], - parameters: { - component: CtaAlert, - chromatic: { - enableDarkMode: true, - disableSnapshot: false, - }, - }, -} - -export default config - -export const Default: Story = () => ( - } - onClose={() => {}} - /> -) -Default.storyName = 'CtaAlert' diff --git a/client/shared/src/components/CtaAlert.tsx b/client/shared/src/components/CtaAlert.tsx deleted file mode 100644 index 7e9d173664890..0000000000000 --- a/client/shared/src/components/CtaAlert.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React from 'react' - -import { mdiClose } from '@mdi/js' -import classNames from 'classnames' - -import { Button, Card, Link, Icon } from '@sourcegraph/wildcard' - -import styles from './CtaAlert.module.scss' - -export interface CtaAlertProps { - title: string - description: string | React.ReactNode - cta: { - label: string - href: string - onClick?: () => void - } - secondary?: { - label: string - href: string - onClick?: () => void - } - icon: React.ReactNode - className?: string - onClose: () => void -} - -export const CtaAlert: React.FunctionComponent> = props => ( - -
{props.icon}
-
-
- {props.title} -
-
{props.description}
- - {props.secondary ? ( - - ) : null} -
- -
-) diff --git a/client/vscode/src/webview/search-panel/SearchResultsView.tsx b/client/vscode/src/webview/search-panel/SearchResultsView.tsx index dffa9f3e380f0..7a9441bfa5e63 100644 --- a/client/vscode/src/webview/search-panel/SearchResultsView.tsx +++ b/client/vscode/src/webview/search-panel/SearchResultsView.tsx @@ -19,7 +19,6 @@ import { } from '@sourcegraph/search-ui' import { wrapRemoteObservable } from '@sourcegraph/shared/src/api/client/api/common' import { fetchHighlightedFileLineRanges } from '@sourcegraph/shared/src/backend/file' -import { CtaAlert } from '@sourcegraph/shared/src/components/CtaAlert' import { collectMetrics } from '@sourcegraph/shared/src/search/query/metrics' import { appendContextFilter, @@ -30,14 +29,12 @@ import { LATEST_VERSION, RepositoryMatch, SearchMatch } from '@sourcegraph/share import { globbingEnabledFromSettings } from '@sourcegraph/shared/src/util/globbing' import { buildSearchURLQuery } from '@sourcegraph/shared/src/util/url' -import { VSCE_LINK_AUTH } from '../../common/links' import { DISMISS_SEARCH_CTA_KEY } from '../../settings/LocalStorageService' import { SearchResultsState } from '../../state' import { WebviewPageProps } from '../platform/context' import { fetchSearchContexts } from './alias/fetchSearchContext' import { setFocusSearchBox } from './api' -import { SearchBetaIcon } from './components/icons' import { SavedSearchCreateForm } from './components/SavedSearchForm' import { SearchResultsInfoBar } from './components/SearchResultsInfoBar' import { MatchHandlersContext, useMatchHandlers } from './MatchHandlersContext' @@ -389,21 +386,6 @@ export const SearchResultsView: React.FunctionComponent - {isSourcegraphDotCom && !authenticatedUser && !dismissSearchCta && ( - } - className={classNames('percy-display-none', styles.ctaContainer)} - onClose={onDismissCtaAlert} - /> - )} Date: Thu, 14 Jul 2022 10:24:48 +0300 Subject: [PATCH 10/18] move VSCode icon to file where it's used --- client/web/src/auth/VsCodeSignUpPage.tsx | 10 +++++++++- client/web/src/components/CtaIcons.tsx | 9 --------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/client/web/src/auth/VsCodeSignUpPage.tsx b/client/web/src/auth/VsCodeSignUpPage.tsx index ae82ca6b256e7..c02a72ba114c9 100644 --- a/client/web/src/auth/VsCodeSignUpPage.tsx +++ b/client/web/src/auth/VsCodeSignUpPage.tsx @@ -9,7 +9,6 @@ import { ThemeProps } from '@sourcegraph/shared/src/theme' import { Link, Icon, H2 } from '@sourcegraph/wildcard' import { BrandLogo } from '../components/branding/BrandLogo' -import { VSCodeIcon } from '../components/CtaIcons' import { AuthProvider, SourcegraphContext } from '../jscontext' import { ExternalsAuth } from './ExternalsAuth' @@ -26,6 +25,15 @@ interface Props extends ThemeProps, TelemetryProps { context: Pick } +const VSCodeIcon: React.FC = () => ( + + + +) + /** * Sign up page specifically from users via our VS Code integration */ diff --git a/client/web/src/components/CtaIcons.tsx b/client/web/src/components/CtaIcons.tsx index e58d25d99d344..468b9525d5790 100644 --- a/client/web/src/components/CtaIcons.tsx +++ b/client/web/src/components/CtaIcons.tsx @@ -116,12 +116,3 @@ export const CodeMonitorRadialGradientIcon = React.memo(() => ( )) - -export const VSCodeIcon = React.memo(({ width = 30, height = 30 }: { width?: number; height?: number } = {}) => ( - - - -)) From 93c0c5548703df3881b953619897d11c8108b5ff Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 10:25:31 +0300 Subject: [PATCH 11/18] remove mentions on site admin pings page --- .../web/src/site-admin/SiteAdminPingsPage.tsx | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/client/web/src/site-admin/SiteAdminPingsPage.tsx b/client/web/src/site-admin/SiteAdminPingsPage.tsx index 7490774585bf5..a21d91763c289 100644 --- a/client/web/src/site-admin/SiteAdminPingsPage.tsx +++ b/client/web/src/site-admin/SiteAdminPingsPage.tsx @@ -346,37 +346,6 @@ export const SiteAdminPingsPage: React.FunctionComponentTotal number of added notebook compute blocks -
  • - CTA usage data -
      -
    • - Browser extension -
        -
      • - Number of users who viewed / clicked the "install browser extension" CTA on the file - / search pages today -
      • -
      • - Number of views / clicks on the "install browser extension" CTA on the file / search - pages today -
      • -
      -
    • -
    • - IDE extension -
        -
      • - Number of users who viewed / clicked the "install IDE extension" CTA on the file / - search pages today -
      • -
      • - Number of views / clicks on the "install IDE extension" CTA on the file / search - pages today -
      • -
      -
    • -
    -
  • Code Host integration usage data (Browser extension / Native Integration)
      From a53cda2747c4b62c5450670b67356deda54b5998 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 11:26:42 +0300 Subject: [PATCH 12/18] wip: remove pings --- .../internal/app/updatecheck/client.go | 16 -------------- .../internal/app/updatecheck/handler.go | 3 --- .../internal/app/updatecheck/handler_test.go | 6 ------ doc/admin/pings.md | 21 ------------------- 4 files changed, 46 deletions(-) diff --git a/cmd/frontend/internal/app/updatecheck/client.go b/cmd/frontend/internal/app/updatecheck/client.go index 1f12628d1ecb3..6c7cc4e8abda6 100644 --- a/cmd/frontend/internal/app/updatecheck/client.go +++ b/cmd/frontend/internal/app/updatecheck/client.go @@ -146,16 +146,6 @@ func getAndMarshalGrowthStatisticsJSON(ctx context.Context, db database.DB) (_ j return json.Marshal(growthStatistics) } -func getAndMarshalCTAUsageJSON(ctx context.Context, db database.DB) (_ json.RawMessage, err error) { - defer recordOperation("getAndMarshalCTAUsageJSON")(&err) - - ctaUsage, err := usagestats.GetCTAUsage(ctx, db) - if err != nil { - return nil, err - } - return json.Marshal(ctaUsage) -} - func getAndMarshalSavedSearchesJSON(ctx context.Context, db database.DB) (_ json.RawMessage, err error) { defer recordOperation("getAndMarshalSavedSearchesJSON")(&err) @@ -394,7 +384,6 @@ func updateBody(ctx context.Context, db database.DB) (io.Reader, error) { SearchUsage: []byte("{}"), BatchChangesUsage: []byte("{}"), GrowthStatistics: []byte("{}"), - CTAUsage: []byte("{}"), SavedSearches: []byte("{}"), HomepagePanels: []byte("{}"), Repositories: []byte("{}"), @@ -472,11 +461,6 @@ func updateBody(ctx context.Context, db database.DB) (io.Reader, error) { logFunc("telemetry: updatecheck.getAndMarshalGrowthStatisticsJSON failed", "error", err) } - r.CTAUsage, err = getAndMarshalCTAUsageJSON(ctx, db) - if err != nil { - logFunc("telemetry: updatecheck.getAndMarshalCTAUsageJSON failed", "error", err) - } - r.SavedSearches, err = getAndMarshalSavedSearchesJSON(ctx, db) if err != nil { logFunc("telemetry: updatecheck.getAndMarshalSavedSearchesJSON failed", "error", err) diff --git a/cmd/frontend/internal/app/updatecheck/handler.go b/cmd/frontend/internal/app/updatecheck/handler.go index 801f5b75cfb75..6fd6f2ddde287 100644 --- a/cmd/frontend/internal/app/updatecheck/handler.go +++ b/cmd/frontend/internal/app/updatecheck/handler.go @@ -181,7 +181,6 @@ type pingRequest struct { // AutomationUsage (campaigns) is deprecated, but here so we can receive pings from older instances AutomationUsage json.RawMessage `json:"automationUsage"` GrowthStatistics json.RawMessage `json:"growthStatistics"` - CTAUsage json.RawMessage `json:"ctaUsage"` SavedSearches json.RawMessage `json:"savedSearches"` HomepagePanels json.RawMessage `json:"homepagePanels"` SearchOnboarding json.RawMessage `json:"searchOnboarding"` @@ -296,7 +295,6 @@ type pingPayload struct { NewCodeIntelUsage json.RawMessage `json:"new_code_intel_usage"` SearchUsage json.RawMessage `json:"search_usage"` GrowthStatistics json.RawMessage `json:"growth_statistics"` - CTAUsage json.RawMessage `json:"cta_usage"` SavedSearches json.RawMessage `json:"saved_searches"` HomepagePanels json.RawMessage `json:"homepage_panels"` RetentionStatistics json.RawMessage `json:"retention_statistics"` @@ -384,7 +382,6 @@ func marshalPing(pr *pingRequest, hasUpdate bool, clientAddr string, now time.Ti NewCodeIntelUsage: codeIntelUsage, SearchUsage: searchUsage, GrowthStatistics: pr.GrowthStatistics, - CTAUsage: pr.CTAUsage, SavedSearches: pr.SavedSearches, HomepagePanels: pr.HomepagePanels, RetentionStatistics: pr.RetentionStatistics, diff --git a/cmd/frontend/internal/app/updatecheck/handler_test.go b/cmd/frontend/internal/app/updatecheck/handler_test.go index 4f900adeea8e0..cbb981b6756b3 100644 --- a/cmd/frontend/internal/app/updatecheck/handler_test.go +++ b/cmd/frontend/internal/app/updatecheck/handler_test.go @@ -187,7 +187,6 @@ func TestSerializeBasic(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "search_usage": null, "growth_statistics": null, "saved_searches": null, @@ -256,7 +255,6 @@ func TestSerializeFromQuery(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "search_usage": null, "growth_statistics": null, "saved_searches": null, @@ -336,7 +334,6 @@ func TestSerializeBatchChangesUsage(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "search_usage": null, "growth_statistics": null, "saved_searches": null, @@ -612,7 +609,6 @@ func TestSerializeCodeIntelUsage(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "dependency_versions": null, "extensions_usage": null, "code_insights_usage": null, @@ -783,7 +779,6 @@ func TestSerializeOldCodeIntelUsage(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "dependency_versions": null, "extensions_usage": null, "code_insights_usage": null, @@ -867,7 +862,6 @@ func TestSerializeCodeHostVersions(t *testing.T) { "notebooks_usage": null, "code_host_integration_usage": null, "ide_extensions_usage": null, - "cta_usage": null, "search_usage": null, "growth_statistics": null, "saved_searches": null, diff --git a/doc/admin/pings.md b/doc/admin/pings.md index 81aec1a453967..d58913c369e60 100644 --- a/doc/admin/pings.md +++ b/doc/admin/pings.md @@ -164,27 +164,6 @@ This telemetry can be disabled using the `disableNonCriticalTelemetry` option in - Count of users who uninstalled the extension - Aggregate count of current daily redirects from extension to Sourcegraph instance - - -- CTA usage data - - Browser extension - - Total number of users who viewed the "install browser extension" CTA on the file page - - Total number of users who clicked the "install browser extension" CTA on the file page - - Total number of users who viewed the "install browser extension" CTA on the search page - - Total number of users who clicked the "install browser extension" CTA on the search page - - Total number of views of the "install browser extension" CTA on the file page - - Total number of clicks on the "install browser extension" CTA on the file page - - Total number of views of the "install browser extension" CTA on the search page - - Total number of clicks on the "install browser extension" CTA on the search page - -- CTA usage data - - Browser extension - - Number of users who viewed / clicked the "install browser extension" CTA on the file / search pages today - - Number of views / clicks on the "install browser extension" CTA on the file / search pages today - - IDE extension - - Number of users who viewed / clicked the "install IDE extension" CTA on the file / search pages today - - Number of views / clicks on the "install IDE extension" CTA on the file / search pages today - ## CIDR Range for Sourcegraph Sourcegraph currently uses Cloudflare to provide web application security. You should allow access to all [Cloudflare IP ranges](https://www.cloudflare.com/ips/) From 8bff58c1eb821c4df9e11bff79d80d380e89ed73 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 11:28:22 +0300 Subject: [PATCH 13/18] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index edf244537838c..58b3ede60350e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ All notable changes to Sourcegraph are documented in this file. - The direct DataDog trace export integration has been removed. ([#37654](https://github.com/sourcegraph/sourcegraph/pull/37654)) - Removed the deprecated git exec forwarder. [#38092](https://github.com/sourcegraph/sourcegraph/pull/38092) +- Browser and IDE extensions banners. [#38715](https://github.com/sourcegraph/sourcegraph/pull/38715) ## 3.41.0 From 6f625c708faf9d22ef5240b6587d3ac161b225cf Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 11:45:28 +0300 Subject: [PATCH 14/18] remove CTA usage stats collection --- internal/types/types.go | 24 ------ internal/usagestats/growth.go | 115 -------------------------- internal/usagestats/growth_test.go | 126 ----------------------------- 3 files changed, 265 deletions(-) delete mode 100644 internal/usagestats/growth_test.go diff --git a/internal/types/types.go b/internal/types/types.go index c89e96e2652d1..d911db4ac1198 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -1230,30 +1230,6 @@ type CodeHostIntegrationUsageInboundTrafficToWeb struct { TotalCount int32 } -// UserAndEventCount represents the number of events triggered in a given -// time frame per user and overall. -type UserAndEventCount struct { - UserCount int32 - EventCount int32 -} - -// FileAndSearchPageUserAndEventCounts represents the number of events triggered -// on the "search result" and "file" pages in a given time frame. -type FileAndSearchPageUserAndEventCounts struct { - StartTime time.Time - DisplayedOnFilePage UserAndEventCount - DisplayedOnSearchPage UserAndEventCount - ClickedOnFilePage UserAndEventCount - ClickedOnSearchPage UserAndEventCount -} - -// CTAUsage represents the total number of CTAs displayed and clicked -// on the "search result" and "file" pages over the current month. -type CTAUsage struct { - DailyBrowserExtensionCTA FileAndSearchPageUserAndEventCounts - DailyIDEExtensionCTA FileAndSearchPageUserAndEventCounts -} - // SavedSearches represents the total number of saved searches, users // using saved searches, and usage of saved searches. type SavedSearches struct { diff --git a/internal/usagestats/growth.go b/internal/usagestats/growth.go index 5a7026aed25ac..4a0081d4f7c93 100644 --- a/internal/usagestats/growth.go +++ b/internal/usagestats/growth.go @@ -4,7 +4,6 @@ package usagestats import ( "context" - "time" "github.com/sourcegraph/sourcegraph/internal/database" "github.com/sourcegraph/sourcegraph/internal/types" @@ -74,117 +73,3 @@ SELECT COUNT(*) FILTER ( WHERE recent_usage_by_user.created_month = DATE_TRUNC(' RetainedUsers: int32(retainedUsers), }, nil } - -func GetCTAUsage(ctx context.Context, db database.DB) (*types.CTAUsage, error) { - // aggregatedUserIDQueryFragment is a query fragment that can be used to canonicalize the - // values of the user_id and anonymous_user_id fields (assumed in scope) int a unified value. - const aggregatedUserIDQueryFragment = ` -CASE WHEN user_id = 0 - -- It's faster to group by an int rather than text, so we convert - -- the anonymous_user_id to an int, rather than the user_id to text. - THEN ('x' || substr(md5(anonymous_user_id), 1, 8))::bit(32)::int - ELSE user_id -END -` - - const q = ` - -- source: internal/usagestats/growth.go:GetCTAUsage - WITH events_for_today AS ( - (SELECT name, - ` + aggregatedUserIDQueryFragment + ` AS user_id, - DATE_TRUNC('day', timestamp) AS day, - argument->>'page' AS page - FROM event_logs - WHERE name IN ('InstallBrowserExtensionCTAShown', - 'InstallBrowserExtensionCTAClicked', - 'InstallIDEExtensionCTAShown', - 'InstallIDEExtensionCTAClicked') - AND argument->>'page' IN ('file', 'search') - AND DATE_TRUNC('day', timestamp) = DATE_TRUNC('day', $1::timestamp) - ) UNION ALL ( - SELECT NULL AS name, - NULL AS user_id, - DATE_TRUNC('day', $1::timestamp) AS day, - NULL AS page - ) - ) - SELECT day, - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallBrowserExtensionCTAShown' AND page = 'file'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallBrowserExtensionCTAClicked' AND page = 'file'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallBrowserExtensionCTAShown' AND page = 'search'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallBrowserExtensionCTAClicked' AND page = 'search'), - COUNT(*) FILTER (WHERE name = 'InstallBrowserExtensionCTAShown' AND page = 'file'), - COUNT(*) FILTER (WHERE name = 'InstallBrowserExtensionCTAClicked' AND page = 'file'), - COUNT(*) FILTER (WHERE name = 'InstallBrowserExtensionCTAShown' AND page = 'search'), - COUNT(*) FILTER (WHERE name = 'InstallBrowserExtensionCTAClicked' AND page = 'search'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallIDEExtensionCTAShown' AND page = 'file'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallIDEExtensionCTAClicked' AND page = 'file'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallIDEExtensionCTAShown' AND page = 'search'), - COUNT(DISTINCT user_id) FILTER (WHERE name = 'InstallIDEExtensionCTAClicked' AND page = 'search'), - COUNT(*) FILTER (WHERE name = 'InstallIDEExtensionCTAShown' AND page = 'file'), - COUNT(*) FILTER (WHERE name = 'InstallIDEExtensionCTAClicked' AND page = 'file'), - COUNT(*) FILTER (WHERE name = 'InstallIDEExtensionCTAShown' AND page = 'search'), - COUNT(*) FILTER (WHERE name = 'InstallIDEExtensionCTAClicked' AND page = 'search') - FROM events_for_today - GROUP BY day -` - - var ( - day time.Time - bextFilePageUserDisplays int32 - bextFilePageUserClicks int32 - bextSearchPageUserDisplays int32 - bextSearchPageUserClicks int32 - bextFilePageDisplays int32 - bextFilePageClicks int32 - bextSearchPageDisplays int32 - bextSearchPageClicks int32 - ideFilePageUserDisplays int32 - ideFilePageUserClicks int32 - ideSearchPageUserDisplays int32 - ideSearchPageUserClicks int32 - ideFilePageDisplays int32 - ideFilePageClicks int32 - ideSearchPageDisplays int32 - ideSearchPageClicks int32 - ) - now := timeNow() - if err := db.QueryRowContext(ctx, q, now).Scan( - &day, - &bextFilePageUserDisplays, - &bextFilePageUserClicks, - &bextSearchPageUserDisplays, - &bextSearchPageUserClicks, - &bextFilePageDisplays, - &bextFilePageClicks, - &bextSearchPageDisplays, - &bextSearchPageClicks, - &ideFilePageUserDisplays, - &ideFilePageUserClicks, - &ideSearchPageUserDisplays, - &ideSearchPageUserClicks, - &ideFilePageDisplays, - &ideFilePageClicks, - &ideSearchPageDisplays, - &ideSearchPageClicks, - ); err != nil { - return nil, err - } - - return &types.CTAUsage{ - DailyBrowserExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: day, - DisplayedOnFilePage: types.UserAndEventCount{UserCount: bextFilePageUserDisplays, EventCount: bextFilePageDisplays}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: bextSearchPageUserDisplays, EventCount: bextSearchPageDisplays}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: bextFilePageUserClicks, EventCount: bextFilePageClicks}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: bextSearchPageUserClicks, EventCount: bextSearchPageClicks}, - }, - DailyIDEExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: day, - DisplayedOnFilePage: types.UserAndEventCount{UserCount: ideFilePageUserDisplays, EventCount: ideFilePageDisplays}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: ideSearchPageUserDisplays, EventCount: ideSearchPageDisplays}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: ideFilePageUserClicks, EventCount: ideFilePageClicks}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: ideSearchPageUserClicks, EventCount: ideSearchPageClicks}, - }, - }, nil -} diff --git a/internal/usagestats/growth_test.go b/internal/usagestats/growth_test.go deleted file mode 100644 index 26372d35f4560..0000000000000 --- a/internal/usagestats/growth_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package usagestats - -import ( - "context" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - - "github.com/sourcegraph/log/logtest" - - "github.com/sourcegraph/sourcegraph/internal/database" - "github.com/sourcegraph/sourcegraph/internal/database/dbtest" - "github.com/sourcegraph/sourcegraph/internal/types" -) - -func TestCTAUsageUsageStatisticsWithNoRows(t *testing.T) { - ctx := context.Background() - - defer func() { - timeNow = time.Now - }() - - now := time.Date(2021, 1, 20, 15, 55, 0, 0, time.UTC) - mockTimeNow(now) - - logger := logtest.Scoped(t) - db := database.NewDB(logger, dbtest.NewDB(logger, t)) - - have, err := GetCTAUsage(ctx, db) - if err != nil { - t.Fatal(err) - } - - want := &types.CTAUsage{ - DailyBrowserExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: time.Date(2021, 1, 20, 0, 0, 0, 0, time.UTC), - DisplayedOnFilePage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - }, - DailyIDEExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: time.Date(2021, 1, 20, 0, 0, 0, 0, time.UTC), - DisplayedOnFilePage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: 0, EventCount: 0}, - }, - } - if diff := cmp.Diff(want, have); diff != "" { - t.Fatal(diff) - } -} - -func TestCTAUsageUsageStatisticsWithRows(t *testing.T) { - ctx := context.Background() - - defer func() { - timeNow = time.Now - }() - - now := time.Date(2021, 1, 20, 15, 55, 0, 0, time.UTC) - mockTimeNow(now) - - logger := logtest.Scoped(t) - db := database.NewDB(logger, dbtest.NewDB(logger, t)) - - _, err := db.ExecContext(context.Background(), ` - INSERT INTO event_logs - (id, name, argument, url, user_id, anonymous_user_id, source, version, timestamp) - VALUES - -- Current day event logs - -- user_id=1 - (1, 'InstallBrowserExtensionCTAShown', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (2, 'InstallBrowserExtensionCTAClicked', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (3, 'InstallBrowserExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (4, 'InstallBrowserExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (5, 'InstallBrowserExtensionCTAClicked', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (6, 'InstallIDEExtensionCTAShown', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (7, 'InstallIDEExtensionCTAClicked', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - - -- user_id=0, anonymous user - (8, 'InstallBrowserExtensionCTAShown', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (9, 'InstallBrowserExtensionCTAClicked', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (10, 'InstallBrowserExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (11, 'InstallBrowserExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (12, 'InstallIDEExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - (13, 'InstallIDEExtensionCTAClicked', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 0, '560657f0-d443-4d16-ac7d-003d8cdc9999', 'WEB', '3.23.0', $1::timestamp - interval '1 hour'), - - -- Previous day event logs - (14, 'InstallBrowserExtensionCTAShown', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 day'), - (15, 'InstallBrowserExtensionCTAClicked', '{"page": "file"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 day'), - (16, 'InstallBrowserExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 day'), - (17, 'InstallBrowserExtensionCTAClicked', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 day'), - (18, 'InstallIDEExtensionCTAShown', '{"page": "search"}', 'https://sourcegraph.test:3443/search', 1, '420657f0-d443-4d16-ac7d-003d8cdc91ef', 'WEB', '3.23.0', $1::timestamp - interval '1 day') - `, now) - if err != nil { - t.Fatal(err) - } - - have, err := GetCTAUsage(ctx, db) - if err != nil { - t.Fatal(err) - } - - want := &types.CTAUsage{ - DailyBrowserExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: time.Date(2021, 1, 20, 0, 0, 0, 0, time.UTC), - DisplayedOnFilePage: types.UserAndEventCount{UserCount: 2, EventCount: 2}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: 2, EventCount: 4}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: 2, EventCount: 2}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: 1, EventCount: 1}, - }, - DailyIDEExtensionCTA: types.FileAndSearchPageUserAndEventCounts{ - StartTime: time.Date(2021, 1, 20, 0, 0, 0, 0, time.UTC), - DisplayedOnFilePage: types.UserAndEventCount{UserCount: 1, EventCount: 1}, - DisplayedOnSearchPage: types.UserAndEventCount{UserCount: 1, EventCount: 1}, - ClickedOnFilePage: types.UserAndEventCount{UserCount: 1, EventCount: 1}, - ClickedOnSearchPage: types.UserAndEventCount{UserCount: 1, EventCount: 1}, - }, - } - if diff := cmp.Diff(want, have); diff != "" { - t.Fatal(diff) - } -} From 221f3bf503174b1c6b7b3c1cbced412d7413bbf7 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 12:44:35 +0300 Subject: [PATCH 15/18] remove leftovers --- client/web/src/Layout.tsx | 1 - client/web/src/nav/GlobalNavbar.story.tsx | 1 - client/web/src/nav/GlobalNavbar.test.tsx | 1 - client/web/src/nav/GlobalNavbar.tsx | 3 +-- client/web/src/nav/UserNavItem.story.tsx | 1 - client/web/src/nav/UserNavItem.test.tsx | 2 -- client/web/src/nav/UserNavItem.tsx | 23 +---------------------- 7 files changed, 2 insertions(+), 30 deletions(-) diff --git a/client/web/src/Layout.tsx b/client/web/src/Layout.tsx index 743e1648cf50e..4100d1822ae85 100644 --- a/client/web/src/Layout.tsx +++ b/client/web/src/Layout.tsx @@ -240,7 +240,6 @@ export const Layout: React.FunctionComponent )} diff --git a/client/web/src/nav/GlobalNavbar.story.tsx b/client/web/src/nav/GlobalNavbar.story.tsx index 18bd883b10d09..28e642facc5f8 100644 --- a/client/web/src/nav/GlobalNavbar.story.tsx +++ b/client/web/src/nav/GlobalNavbar.story.tsx @@ -45,7 +45,6 @@ const defaultProps = ( setSelectedSearchContextSpec: () => undefined, defaultSearchContextSpec: '', isLightTheme: props.isLightTheme, - isExtensionAlertAnimating: false, searchContextsEnabled: true, batchChangesEnabled: true, batchChangesExecutionEnabled: true, diff --git a/client/web/src/nav/GlobalNavbar.test.tsx b/client/web/src/nav/GlobalNavbar.test.tsx index af2ae51268eee..d1a9adb1c2f96 100644 --- a/client/web/src/nav/GlobalNavbar.test.tsx +++ b/client/web/src/nav/GlobalNavbar.test.tsx @@ -37,7 +37,6 @@ const PROPS: React.ComponentProps = { batchChangesExecutionEnabled: false, batchChangesWebhookLogsEnabled: false, telemetryService: {} as any, - isExtensionAlertAnimating: false, showSearchBox: true, selectedSearchContextSpec: '', setSelectedSearchContextSpec: () => undefined, diff --git a/client/web/src/nav/GlobalNavbar.tsx b/client/web/src/nav/GlobalNavbar.tsx index 73549a80bf6fc..93c523f2e2611 100644 --- a/client/web/src/nav/GlobalNavbar.tsx +++ b/client/web/src/nav/GlobalNavbar.tsx @@ -58,7 +58,7 @@ import { showDotComMarketing } from '../util/features' import { NavDropdown, NavDropdownItem } from './NavBar/NavDropdown' import { StatusMessagesNavItem } from './StatusMessagesNavItem' -import { ExtensionAlertAnimationProps, UserNavItem } from './UserNavItem' +import { UserNavItem } from './UserNavItem' import { NavGroup, NavItem, NavBar, NavLink, NavActions, NavAction } from '.' @@ -72,7 +72,6 @@ interface Props TelemetryProps, ThemeProps, ThemePreferenceProps, - ExtensionAlertAnimationProps, ActivationProps, SearchContextInputProps, CodeInsightsProps, diff --git a/client/web/src/nav/UserNavItem.story.tsx b/client/web/src/nav/UserNavItem.story.tsx index b0eff54f2997e..859fa0018f9dc 100644 --- a/client/web/src/nav/UserNavItem.story.tsx +++ b/client/web/src/nav/UserNavItem.story.tsx @@ -63,7 +63,6 @@ const commonProps = (): UserNavItemProps => ({ isLightTheme: true, onThemePreferenceChange, showDotComMarketing: boolean('showDotComMarketing', true), - isExtensionAlertAnimating: false, codeHostIntegrationMessaging: select( 'codeHostIntegrationMessaging', ['browser-extension', 'native-integration'] as const, diff --git a/client/web/src/nav/UserNavItem.test.tsx b/client/web/src/nav/UserNavItem.test.tsx index b4dcf770ad62d..1b5215af39037 100644 --- a/client/web/src/nav/UserNavItem.test.tsx +++ b/client/web/src/nav/UserNavItem.test.tsx @@ -62,7 +62,6 @@ describe('UserNavItem', () => { themePreference={ThemePreference.Light} authenticatedUser={USER} showDotComMarketing={true} - isExtensionAlertAnimating={false} codeHostIntegrationMessaging="browser-extension" /> @@ -80,7 +79,6 @@ describe('UserNavItem', () => { themePreference={ThemePreference.Light} authenticatedUser={USER} showDotComMarketing={true} - isExtensionAlertAnimating={false} codeHostIntegrationMessaging="browser-extension" />, { diff --git a/client/web/src/nav/UserNavItem.tsx b/client/web/src/nav/UserNavItem.tsx index 95ec512963664..f089c8961751b 100644 --- a/client/web/src/nav/UserNavItem.tsx +++ b/client/web/src/nav/UserNavItem.tsx @@ -4,7 +4,6 @@ import { mdiChevronDown, mdiChevronUp, mdiOpenInNew } from '@mdi/js' import { Shortcut } from '@slimsag/react-shortcuts' import classNames from 'classnames' // eslint-disable-next-line no-restricted-imports -import { Tooltip } from 'reactstrap' import { KeyboardShortcut } from '@sourcegraph/shared/src/keyboardShortcuts' import { KEYBOARD_SHORTCUT_SHOW_HELP } from '@sourcegraph/shared/src/keyboardShortcuts/keyboardShortcuts' @@ -33,7 +32,7 @@ import { UserAvatar } from '../user/UserAvatar' import styles from './UserNavItem.module.scss' -export interface UserNavItemProps extends ThemeProps, ThemePreferenceProps, ExtensionAlertAnimationProps { +export interface UserNavItemProps extends ThemeProps, ThemePreferenceProps { authenticatedUser: Pick< AuthenticatedUser, 'username' | 'avatarURL' | 'settingsURL' | 'organizations' | 'siteAdmin' | 'session' | 'displayName' @@ -46,10 +45,6 @@ export interface UserNavItemProps extends ThemeProps, ThemePreferenceProps, Exte menuButtonRef?: React.Ref } -export interface ExtensionAlertAnimationProps { - isExtensionAlertAnimating: boolean -} - /** * Triggers Keyboard Shortcut help when the button is clicked in the Menu Nav item */ @@ -75,7 +70,6 @@ export const UserNavItem: React.FunctionComponent - {isExtensionAlertAnimating && ( - - Install the browser extension from here later - - )} From e401533449004b616b54322d7cef8d77efbbaafd Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 12:52:42 +0300 Subject: [PATCH 16/18] remove leftover --- client/web/src/nav/UserNavItem.module.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/web/src/nav/UserNavItem.module.scss b/client/web/src/nav/UserNavItem.module.scss index 6e12bb15429d5..2f7be50659249 100644 --- a/client/web/src/nav/UserNavItem.module.scss +++ b/client/web/src/nav/UserNavItem.module.scss @@ -61,11 +61,6 @@ border-top: 1px solid var(--border-color-2); } -.tooltip { - opacity: 0; - animation: tooltip-fade-in-out 5s ease-out 100ms; -} - .avatar { height: 1.5rem; width: 1.5rem; From a948ffe70b28dea58a3b48969de6ce3649c99c10 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 13:15:27 +0300 Subject: [PATCH 17/18] remove vscode leftovers --- .../vscode/src/settings/LocalStorageService.ts | 1 - .../webview/search-panel/SearchResultsView.tsx | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/client/vscode/src/settings/LocalStorageService.ts b/client/vscode/src/settings/LocalStorageService.ts index 4415eaa80ff77..4b6b4c5ce58b3 100644 --- a/client/vscode/src/settings/LocalStorageService.ts +++ b/client/vscode/src/settings/LocalStorageService.ts @@ -22,5 +22,4 @@ export class LocalStorageService { export const SELECTED_SEARCH_CONTEXT_SPEC_KEY = 'selected-search-context-spec' export const INSTANCE_VERSION_NUMBER_KEY = 'sourcegraphVersionNumber' export const ANONYMOUS_USER_ID_KEY = 'sourcegraphAnonymousUid' -export const DISMISS_SEARCH_CTA_KEY = 'sourcegraphSearchCtaDismissed' export const DISMISS_WORKSPACERECS_CTA_KEY = 'sourcegraphWorkspaceRecsCtaDismissed' diff --git a/client/vscode/src/webview/search-panel/SearchResultsView.tsx b/client/vscode/src/webview/search-panel/SearchResultsView.tsx index 7a9441bfa5e63..13748f175f3b2 100644 --- a/client/vscode/src/webview/search-panel/SearchResultsView.tsx +++ b/client/vscode/src/webview/search-panel/SearchResultsView.tsx @@ -29,7 +29,6 @@ import { LATEST_VERSION, RepositoryMatch, SearchMatch } from '@sourcegraph/share import { globbingEnabledFromSettings } from '@sourcegraph/shared/src/util/globbing' import { buildSearchURLQuery } from '@sourcegraph/shared/src/util/url' -import { DISMISS_SEARCH_CTA_KEY } from '../../settings/LocalStorageService' import { SearchResultsState } from '../../state' import { WebviewPageProps } from '../platform/context' @@ -61,28 +60,11 @@ export const SearchResultsView: React.FunctionComponent | null>(null) - // Check VS Code local storage to see if user has clicked dismiss button before - const [dismissSearchCta, setDismissSearchCta] = useState(false) - // Return empty string if not in vs code local storage or 'search' if it exists - const showCtaAlert = useMemo(() => extensionCoreAPI.getLocalStorageItem(DISMISS_SEARCH_CTA_KEY), [extensionCoreAPI]) - const onDismissCtaAlert = useCallback(async () => { - setDismissSearchCta(true) - await extensionCoreAPI.setLocalStorageItem(DISMISS_SEARCH_CTA_KEY, 'true') - }, [extensionCoreAPI]) - const isSourcegraphDotCom = useMemo(() => { const hostname = new URL(instanceURL).hostname return hostname === 'sourcegraph.com' || hostname === 'www.sourcegraph.com' }, [instanceURL]) - useEffect(() => { - showCtaAlert - .then(result => { - setDismissSearchCta(result.length > 0) - }) - .catch(() => setDismissSearchCta(false)) - }, [showCtaAlert]) - // Editor focus. const editorReference = useRef() const setEditor = useCallback((editor: IEditor) => { From 3addad442e7d77cd0ba0c42ad1f9c5596091bfb3 Mon Sep 17 00:00:00 2001 From: Taras Yemets Date: Thu, 14 Jul 2022 13:26:05 +0300 Subject: [PATCH 18/18] remove leftover --- .../src/webview/search-panel/SearchResultsView.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/client/vscode/src/webview/search-panel/SearchResultsView.tsx b/client/vscode/src/webview/search-panel/SearchResultsView.tsx index 13748f175f3b2..cd3cec6eef164 100644 --- a/client/vscode/src/webview/search-panel/SearchResultsView.tsx +++ b/client/vscode/src/webview/search-panel/SearchResultsView.tsx @@ -300,18 +300,6 @@ export const SearchResultsView: React.FunctionComponent { - event?.preventDefault() - platformContext.telemetryService.log( - 'VSCECreateAccountBannerClick', - { campaign: 'Sign up link' }, - { campaign: 'Sign up link' } - ) - }, - [platformContext.telemetryService] - ) - const matchHandlers = useMatchHandlers({ platformContext, extensionCoreAPI,