From 123852b66df4b23b3ab8bd70eccd5e46862e9b2f Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Thu, 2 Feb 2023 22:33:08 -0300 Subject: [PATCH 01/11] Add new setup wizard core UI --- .../settings/temporary/TemporarySettings.ts | 1 + client/web/src/Layout.tsx | 6 + client/web/src/SourcegraphWebApp.tsx | 22 +- client/web/src/routes.constants.ts | 1 + client/web/src/setup-wizard/Setup.module.scss | 1 - client/web/src/setup-wizard/SetupWizard.tsx | 50 ++++- .../setup-steps/SetupSteps.module.scss | 80 +++++++ .../components/setup-steps/SetupSteps.tsx | 197 ++++++++++++++++++ .../components/setup-steps/index.ts | 2 + 9 files changed, 338 insertions(+), 22 deletions(-) create mode 100644 client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss create mode 100644 client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx create mode 100644 client/web/src/setup-wizard/components/setup-steps/index.ts diff --git a/client/shared/src/settings/temporary/TemporarySettings.ts b/client/shared/src/settings/temporary/TemporarySettings.ts index e0939414e384..37cf0e946ae1 100644 --- a/client/shared/src/settings/temporary/TemporarySettings.ts +++ b/client/shared/src/settings/temporary/TemporarySettings.ts @@ -58,6 +58,7 @@ export interface TemporarySettingsSchema { 'batches.minSavedPerChangeset': number 'search.notebooks.minSavedPerView': number 'repo.commitPage.diffMode': DiffMode + 'setup.activeStepId': string } /** diff --git a/client/web/src/Layout.tsx b/client/web/src/Layout.tsx index a0ef5b4e10d0..72baab5b0c4a 100644 --- a/client/web/src/Layout.tsx +++ b/client/web/src/Layout.tsx @@ -51,6 +51,7 @@ import type { LayoutRouteComponentProps, LayoutRouteProps } from './routes' import { EnterprisePageRoutes, PageRoutes } from './routes.constants' import { parseSearchURLQuery, SearchAggregationProps, SearchStreamingProps } from './search' import { NotepadContainer } from './search/Notepad' +import { SetupWizard } from './setup-wizard' import type { SiteAdminAreaRoute } from './site-admin/SiteAdminArea' import type { SiteAdminSideBarGroups } from './site-admin/SiteAdminSidebar' import { useTheme, useThemeProps } from './theme' @@ -131,6 +132,7 @@ export const Layout: React.FunctionComponent + if (isSetupWizardPage) { + return + } + return (
this.setState({ authenticatedUser: null }) @@ -337,9 +333,14 @@ export class SourcegraphWebApp extends React.Component } - const { authenticatedUser, graphqlClient, temporarySettingsStorage, isSetupWizardEnabled } = this.state + const { settingsCascade, authenticatedUser, graphqlClient, temporarySettingsStorage } = this.state - if (authenticatedUser === undefined || graphqlClient === undefined || temporarySettingsStorage === undefined) { + if ( + authenticatedUser === undefined || + graphqlClient === undefined || + temporarySettingsStorage === undefined || + !settingsCascade + ) { return null } @@ -363,7 +364,6 @@ export class SourcegraphWebApp extends React.Component - {isSetupWizardEnabled ? } /> : null}

Hello local repositories step

, + }, + { + id: '002', + name: 'Add remote repositories', + path: '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/setup/remote-repositories', + render: () => ( + +

Hello remote repositories step

+ +
+ ), + }, + { + id: '003', + name: 'Sync repositories', + path: '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/setup/sync-repositories', + render: () =>

Hello sync repositories step

, + }, +] + export const SetupWizard: FC = props => { - const [step, setStep] = useState(0) + const [activeStepId, setStepId, status] = useTemporarySetting('setup.activeStepId') + + if (status !== 'loaded') { + return null + } + + const handleStepChange = (step: StepConfiguration): void => { + setStepId(step.id) + } return (
@@ -21,12 +56,7 @@ export const SetupWizard: FC = props => { - - - Add code hosts - Sync repositories - - +
) } diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss new file mode 100644 index 000000000000..8eaeeb2414d9 --- /dev/null +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss @@ -0,0 +1,80 @@ +.root { + display: flex; + flex-direction: column; + gap: 2rem; + flex-grow: 1; + justify-content: center; +} + +.header { + display: flex; + justify-content: space-between; + gap: 2rem; + margin: -1.5rem auto 0; + + &-step { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + } + + &-step-number { + width: 3rem; + height: 3rem; + display: flex; + justify-content: center; + align-items: center; + font-size: 1.5rem; + border-radius: 50%; + border: 2px solid var(--body-bg); + background-color: var(--purple); + color: var(--white); + + &--completed { + background-color: var(--success); + } + + &--disabled { + color: var(--body-color); + background-color: var(--gray-03); + } + } + + &-step-label { + font-weight: bold; + } +} + +.content { + flex-grow: 1; + margin: auto; +} + +.actions { + width: 100%; +} + +.navigation { + display: flex; + padding: 0.5rem; + background-color: var(--gray-02); + + &-inner { + display: flex; + flex-grow: 1; + gap: 0.5rem; + max-width: 40rem; + margin: auto; + } + + // Hide default next button if the custom button is rendered + &-next-portal:not(:empty) + &-next { + display: none; + } + + &-next-portal, + &-next { + margin-left: auto; + } +} diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx new file mode 100644 index 000000000000..bc6d23a1ed96 --- /dev/null +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx @@ -0,0 +1,197 @@ +import { + useRef, + Ref, + createContext, + useState, + FC, + ReactElement, + ReactNode, + HTMLAttributes, + useMemo, + useContext, + useCallback, +} from 'react' + +import { mdiChevronLeft, mdiChevronRight } from '@mdi/js' +import classNames from 'classnames' +import { createPortal } from 'react-dom' +import { Switch, Redirect, Route } from 'react-router' +import { useNavigate } from 'react-router-dom-v5-compat' + +import { Button, Icon } from '@sourcegraph/wildcard' + +import styles from './SetupSteps.module.scss' + +export interface StepConfiguration { + id: string + path: string + name: string + render: ReactElement | (() => ReactNode) +} + +interface SetupStepsContextData { + steps: StepConfiguration[] + nextButtonPortalElement: HTMLDivElement | null + onNextStep: () => void +} + +const SetupStepsContext = createContext({ + steps: [], + nextButtonPortalElement: null, + onNextStep: () => {}, +}) + +interface SetupStepsProps { + initialStepId: string | undefined + steps: StepConfiguration[] + onStepChange: (nextStep: StepConfiguration) => void +} + +export const SetupStepsRoot: FC = props => { + const { initialStepId, steps, onStepChange } = props + + const navigate = useNavigate() + const [stepId, setStepId] = useState(initialStepId) + const nextButtonPortalRef = useRef(null) + + const rawActiveStep = steps.findIndex(step => step.id === stepId) + const activeStepIndex = rawActiveStep !== -1 ? rawActiveStep : 0 + const availableSteps = steps.filter((step, index) => index <= activeStepIndex) + + const handleGoToNextStep = useCallback(() => { + const nextStepIndex = activeStepIndex + 1 + + if (nextStepIndex < steps.length) { + const nextStep = steps[nextStepIndex] + + setStepId(nextStep.id) + navigate(nextStep.path) + onStepChange(nextStep) + } + }, [activeStepIndex, navigate, onStepChange, steps]) + + const handleGoToPrevStep = (): void => { + const prevStepIndex = activeStepIndex - 1 + + if (prevStepIndex >= 0) { + const prevStep = steps[prevStepIndex] + + setStepId(prevStep.id) + navigate(prevStep.path) + onStepChange(prevStep) + } + } + + const cachedContext = useMemo( + () => ({ + steps, + nextButtonPortalElement: nextButtonPortalRef.current, + onNextStep: handleGoToNextStep, + }), + [handleGoToNextStep, steps] + ) + + return ( + +
+ +
+ + {availableSteps.map(step => ( + + {step.render} + + ))} + + + +
+ +
+
+ ) +} + +interface SetupStepsHeaderProps extends HTMLAttributes { + steps: StepConfiguration[] + activeStepIndex: number +} + +export const SetupStepsHeader: FC = props => { + const { steps, activeStepIndex, className, ...attributes } = props + + return ( +
+ {steps.map((step, index) => ( +
+ activeStepIndex, + })} + > + {index + 1} + + {step.name} +
+ ))} +
+ ) +} + +interface SetupStepsFooterProps { + steps: StepConfiguration[] + activeStepIndex: number + nextButtonPortalRef: Ref + onPrevStep: () => void + onNextStep: () => void +} + +export const SetupStepsFooter: FC = props => { + const { steps, activeStepIndex, nextButtonPortalRef, onPrevStep, onNextStep } = props + + return ( +
+
+ {activeStepIndex > 0 && ( + + )} + +
+ +
+
+ ) +} + +interface CustomNextButtonProps { + label: string + disabled: boolean +} + +export const CustomNextButton: FC = props => { + const { label, disabled } = props + const { nextButtonPortalElement, onNextStep } = useContext(SetupStepsContext) + + if (!nextButtonPortalElement) { + return null + } + + return createPortal( + , + nextButtonPortalElement + ) +} diff --git a/client/web/src/setup-wizard/components/setup-steps/index.ts b/client/web/src/setup-wizard/components/setup-steps/index.ts new file mode 100644 index 000000000000..628ccae0f510 --- /dev/null +++ b/client/web/src/setup-wizard/components/setup-steps/index.ts @@ -0,0 +1,2 @@ +export { SetupStepsRoot, CustomNextButton } from './SetupSteps' +export type { StepConfiguration } from './SetupSteps' From 120c98692cc9c361d8341369fb3a0d229f4066f1 Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Fri, 3 Feb 2023 14:54:08 -0300 Subject: [PATCH 02/11] Fix setup wizard experimental flag check and visual background issue --- client/web/src/Layout.tsx | 5 ++++- client/web/src/setup-wizard/Setup.module.scss | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/client/web/src/Layout.tsx b/client/web/src/Layout.tsx index 72baab5b0c4a..2a0f51334b0b 100644 --- a/client/web/src/Layout.tsx +++ b/client/web/src/Layout.tsx @@ -54,6 +54,7 @@ import { NotepadContainer } from './search/Notepad' import { SetupWizard } from './setup-wizard' import type { SiteAdminAreaRoute } from './site-admin/SiteAdminArea' import type { SiteAdminSideBarGroups } from './site-admin/SiteAdminSidebar' +import { useExperimentalFeatures } from './stores' import { useTheme, useThemeProps } from './theme' import type { UserAreaRoute } from './user/area/UserArea' import type { UserAreaHeaderNavItem } from './user/area/UserAreaHeader' @@ -132,7 +133,9 @@ export const Layout: React.FunctionComponent Date: Fri, 3 Feb 2023 15:01:39 -0300 Subject: [PATCH 03/11] Remove old setup tabs UI --- .../components/SetupTabs.module.scss | 50 -------- .../src/setup-wizard/components/SetupTabs.tsx | 113 ------------------ 2 files changed, 163 deletions(-) delete mode 100644 client/web/src/setup-wizard/components/SetupTabs.module.scss delete mode 100644 client/web/src/setup-wizard/components/SetupTabs.tsx diff --git a/client/web/src/setup-wizard/components/SetupTabs.module.scss b/client/web/src/setup-wizard/components/SetupTabs.module.scss deleted file mode 100644 index 02a7d2df2f2a..000000000000 --- a/client/web/src/setup-wizard/components/SetupTabs.module.scss +++ /dev/null @@ -1,50 +0,0 @@ -.tabs { - background-color: unset; -} - -.header-list { - display: flex; - gap: 1rem !important; -} - -.tab { - &[data-selected] { - color: var(--black) !important; - border-bottom: 2px solid var(--primary) !important; - } - - &--completed { - color: var(--black) !important; - border-bottom: 2px solid var(--primary) !important; - } - - &[data-reach-tab] { - color: var(--black) !important; - - &:hover { - border-bottom: none !important; - } - } -} - -.panels { - margin-top: 0; - padding: 1rem; - border-top-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; - border-top: none !important; -} - -.actions { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0.5rem; - padding: 1rem; - margin: 1rem -1rem -1rem -1rem; - border-top: 1px solid var(--border-color); - - &-skip { - margin-right: auto; - } -} diff --git a/client/web/src/setup-wizard/components/SetupTabs.tsx b/client/web/src/setup-wizard/components/SetupTabs.tsx deleted file mode 100644 index 0f8cfd8d0861..000000000000 --- a/client/web/src/setup-wizard/components/SetupTabs.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { createContext, FC, PropsWithChildren, useContext } from 'react' - -import classNames from 'classnames' -import { noop } from 'lodash' - -import { Button, Tab, TabList, TabPanel, Tabs, TabListProps, useTabsContext } from '@sourcegraph/wildcard' - -import styles from './SetupTabs.module.scss' - -interface SetupTabsContextData { - onTabChange: (index: number) => void -} - -const SetupTabsContext = createContext({ - onTabChange: noop, -}) - -interface SetupTabsProps { - activeTabIndex: number - defaultActiveIndex: number - onTabChange: (activeIndex: number) => void -} - -/** - * The root visual element for the setup Tabs UI wizard layout. Enforces - * the right layout and internal state for completed, current and further setup steps - */ -export const SetupTabs: FC> = props => { - const { activeTabIndex, defaultActiveIndex, children, onTabChange } = props - - return ( - - - {children} - - - ) -} - -/** UI component to declare list of steps headers (tabs) UI */ -export const SetupList: FC> = props => ( - -) - -interface SetupTabProps { - index: number -} - -export const SetupTab: FC> = props => { - const { index, children } = props - const { selectedIndex } = useTabsContext() - - return ( - index })} - > - {children} - - ) -} - -export { TabPanel as SetupStep } - -interface SetupStepActions { - nextAvailable: boolean - finish?: boolean - onSkip?: () => void - onComplete?: () => void -} - -export const SetupStepActions: FC = props => { - const { nextAvailable, finish, onSkip, onComplete } = props - - const { selectedIndex } = useTabsContext() - const { onTabChange } = useContext(SetupTabsContext) - - const isFirstStep = selectedIndex === 0 - - return ( -
- {!finish && ( - <> - - {!isFirstStep && ( - - )} - - - )} - - {finish && ( - - )} -
- ) -} From 95efd97712b1f1c9ffb3ef97b76b199748bd37b0 Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Fri, 3 Feb 2023 15:08:05 -0300 Subject: [PATCH 04/11] Fix after rebasing main --- client/web/src/SourcegraphWebApp.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/web/src/SourcegraphWebApp.tsx b/client/web/src/SourcegraphWebApp.tsx index 795d0376e79e..a96e9373e3a4 100644 --- a/client/web/src/SourcegraphWebApp.tsx +++ b/client/web/src/SourcegraphWebApp.tsx @@ -371,11 +371,9 @@ export class SourcegraphWebApp extends React.Component Date: Tue, 7 Feb 2023 14:11:40 -0300 Subject: [PATCH 05/11] Remove top level route --- client/web/src/SourcegraphWebApp.tsx | 76 +++++++++++++--------------- 1 file changed, 34 insertions(+), 42 deletions(-) diff --git a/client/web/src/SourcegraphWebApp.tsx b/client/web/src/SourcegraphWebApp.tsx index a96e9373e3a4..90d450101807 100644 --- a/client/web/src/SourcegraphWebApp.tsx +++ b/client/web/src/SourcegraphWebApp.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import { ApolloProvider } from '@apollo/client' import ServerIcon from 'mdi-react/ServerIcon' import { Router } from 'react-router' -import { CompatRouter, Routes, Route } from 'react-router-dom-v5-compat' +import { CompatRouter } from 'react-router-dom-v5-compat' import { combineLatest, from, Subscription, fromEvent, of, Subject, Observable } from 'rxjs' import { first, startWith, switchMap } from 'rxjs/operators' import * as uuid from 'uuid' @@ -358,50 +358,42 @@ export class SourcegraphWebApp extends React.Component, , , + , /* eslint-enable react/no-children-prop, react/jsx-key */ ]} > - - - - - } - /> - - - + + + {this.extensionsController !== null && window.context.enableLegacyExtensions ? ( Date: Tue, 7 Feb 2023 14:11:52 -0300 Subject: [PATCH 06/11] Use v6 router parts --- .../components/setup-steps/SetupSteps.tsx | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx index bc6d23a1ed96..110be95fd467 100644 --- a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx @@ -4,7 +4,6 @@ import { createContext, useState, FC, - ReactElement, ReactNode, HTMLAttributes, useMemo, @@ -15,8 +14,7 @@ import { import { mdiChevronLeft, mdiChevronRight } from '@mdi/js' import classNames from 'classnames' import { createPortal } from 'react-dom' -import { Switch, Redirect, Route } from 'react-router' -import { useNavigate } from 'react-router-dom-v5-compat' +import { useNavigate, Routes, Route, Navigate } from 'react-router-dom-v5-compat' import { Button, Icon } from '@sourcegraph/wildcard' @@ -26,7 +24,7 @@ export interface StepConfiguration { id: string path: string name: string - render: ReactElement | (() => ReactNode) + render: () => ReactNode } interface SetupStepsContextData { @@ -68,9 +66,9 @@ export const SetupStepsRoot: FC = props => { navigate(nextStep.path) onStepChange(nextStep) } - }, [activeStepIndex, navigate, onStepChange, steps]) + }, [activeStepIndex, steps, navigate, onStepChange]) - const handleGoToPrevStep = (): void => { + const handleGoToPrevStep = useCallback(() => { const prevStepIndex = activeStepIndex - 1 if (prevStepIndex >= 0) { @@ -80,7 +78,7 @@ export const SetupStepsRoot: FC = props => { navigate(prevStep.path) onStepChange(prevStep) } - } + }, [activeStepIndex, steps, navigate, onStepChange]) const cachedContext = useMemo( () => ({ @@ -96,15 +94,12 @@ export const SetupStepsRoot: FC = props => {
- + {availableSteps.map(step => ( - - {step.render} - + ))} - - - + } /> +
Date: Tue, 7 Feb 2023 15:56:41 -0300 Subject: [PATCH 07/11] Adjust colors and fonts for the light/dark theme --- client/web/src/setup-wizard/Setup.module.scss | 9 ++-- client/web/src/setup-wizard/SetupWizard.tsx | 2 +- .../setup-steps/SetupSteps.module.scss | 43 +++++++++++++++---- .../components/setup-steps/SetupSteps.tsx | 2 +- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/client/web/src/setup-wizard/Setup.module.scss b/client/web/src/setup-wizard/Setup.module.scss index f957f495aba4..3c6ee1dff30b 100644 --- a/client/web/src/setup-wizard/Setup.module.scss +++ b/client/web/src/setup-wizard/Setup.module.scss @@ -7,11 +7,12 @@ .header { background: radial-gradient( - 113.96% 113.96% at 50% -8.21%, - var(--violet-06) 0%, - var(--violet-07) 57.81%, - var(--violet-08) 100% + 130.33% 541.14% at 48.47% 231.96%, + var(--violet-06) 17.19%, + var(--violet-07) 43.23%, + var(--violet-07) 73.44% ); + width: 100%; padding: 1.5rem; display: flex; diff --git a/client/web/src/setup-wizard/SetupWizard.tsx b/client/web/src/setup-wizard/SetupWizard.tsx index f15d162c2318..9381284a2b67 100644 --- a/client/web/src/setup-wizard/SetupWizard.tsx +++ b/client/web/src/setup-wizard/SetupWizard.tsx @@ -52,7 +52,7 @@ export const SetupWizard: FC = props => {

- Welcome to Sourcegraph! Let's get your instance ready. + Welcome to Sourcegraph! Let's get started.

diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss index 8eaeeb2414d9..f9f3079b6ea2 100644 --- a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.module.scss @@ -27,22 +27,42 @@ align-items: center; font-size: 1.5rem; border-radius: 50%; - border: 2px solid var(--body-bg); - background-color: var(--purple); - color: var(--white); - &--completed { - background-color: var(--success); + :global(.theme-light) & { + color: var(--white); + border: 2px solid var(--body-bg); + background-color: var(--purple); + + &--completed { + color: #b99dcc; + background-color: #dccde7; + } + + &--disabled { + color: var(--text-muted); + background-color: #d9d9d9; + } } - &--disabled { - color: var(--body-color); - background-color: var(--gray-03); + :global(.theme-dark) & { + color: var(--gray-01); + border: 2px solid var(--gray-01); + background-color: var(--purple); + + &--completed { + color: #b99dcc; + background-color: #dccde7; + } + + &--disabled { + color: var(--text-muted); + background-color: var(--gray-03); + } } } &-step-label { - font-weight: bold; + font-weight: normal; } } @@ -59,6 +79,11 @@ display: flex; padding: 0.5rem; background-color: var(--gray-02); + border-top: 1px solid var(--border-color); + + :global(.theme-dark) & { + background-color: var(--color-bg-2); + } &-inner { display: flex; diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx index 110be95fd467..d45a4c76e6e0 100644 --- a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx @@ -133,7 +133,7 @@ export const SetupStepsHeader: FC = props => { > {index + 1} - {step.name} + {step.name}
))} From 88f10fc393563f2f21844a6a1c3247263d96efa7 Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Tue, 7 Feb 2023 15:59:20 -0300 Subject: [PATCH 08/11] Revert "Remove top level route" This reverts commit 3763721b3ae1e789c59b8396e636978e29c2b0dc. --- client/web/src/SourcegraphWebApp.tsx | 76 +++++++++++++++------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/client/web/src/SourcegraphWebApp.tsx b/client/web/src/SourcegraphWebApp.tsx index 90d450101807..a96e9373e3a4 100644 --- a/client/web/src/SourcegraphWebApp.tsx +++ b/client/web/src/SourcegraphWebApp.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import { ApolloProvider } from '@apollo/client' import ServerIcon from 'mdi-react/ServerIcon' import { Router } from 'react-router' -import { CompatRouter } from 'react-router-dom-v5-compat' +import { CompatRouter, Routes, Route } from 'react-router-dom-v5-compat' import { combineLatest, from, Subscription, fromEvent, of, Subject, Observable } from 'rxjs' import { first, startWith, switchMap } from 'rxjs/operators' import * as uuid from 'uuid' @@ -358,42 +358,50 @@ export class SourcegraphWebApp extends React.Component, , , - , /* eslint-enable react/no-children-prop, react/jsx-key */ ]} > - - - + + + + + } + /> + + + {this.extensionsController !== null && window.context.enableLegacyExtensions ? ( Date: Tue, 7 Feb 2023 17:03:30 -0300 Subject: [PATCH 09/11] Use calculated from URL context instead of local state --- .../components/setup-steps/SetupSteps.tsx | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx index d45a4c76e6e0..507ec4b45054 100644 --- a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx @@ -2,19 +2,19 @@ import { useRef, Ref, createContext, - useState, FC, ReactNode, HTMLAttributes, useMemo, useContext, useCallback, + useEffect, } from 'react' import { mdiChevronLeft, mdiChevronRight } from '@mdi/js' import classNames from 'classnames' import { createPortal } from 'react-dom' -import { useNavigate, Routes, Route, Navigate } from 'react-router-dom-v5-compat' +import { useLocation, useNavigate, Routes, Route, Navigate, matchPath } from 'react-router-dom-v5-compat' import { Button, Icon } from '@sourcegraph/wildcard' @@ -45,16 +45,51 @@ interface SetupStepsProps { onStepChange: (nextStep: StepConfiguration) => void } +interface SetupStepURLContext { + currentStep: StepConfiguration + activeStepIndex: number +} + export const SetupStepsRoot: FC = props => { const { initialStepId, steps, onStepChange } = props const navigate = useNavigate() - const [stepId, setStepId] = useState(initialStepId) + const location = useLocation() const nextButtonPortalRef = useRef(null) - const rawActiveStep = steps.findIndex(step => step.id === stepId) - const activeStepIndex = rawActiveStep !== -1 ? rawActiveStep : 0 - const availableSteps = steps.filter((step, index) => index <= activeStepIndex) + // Resolve current setup step and its index by URL matches + const { currentStep, activeStepIndex } = useMemo(() => { + // Try to find step by URL based on available steps + const urlStepIndex = steps.findIndex(step => matchPath(location.pathname, step.path) !== null) + + if (urlStepIndex !== -1) { + return { + activeStepIndex: urlStepIndex, + currentStep: steps[urlStepIndex], + } + } + + // Try to find step by pre-saved settings if URL doesn't resolve any step + const savedStepIndex = steps.findIndex(step => step.id === initialStepId) + + if (savedStepIndex !== -1) { + return { + activeStepIndex: savedStepIndex, + currentStep: steps[savedStepIndex], + } + } + + // Fallback on the last available step if URL doesn't match any step and we + // don't have any pre-saved step + return { + activeStepIndex: availableSteps.length - 1, + currentStep: availableSteps[availableSteps.length - 1], + } + }, [location, initialStepId, steps]) + + useEffect(() => { + onStepChange(currentStep) + }, [currentStep, onStepChange]) const handleGoToNextStep = useCallback(() => { const nextStepIndex = activeStepIndex + 1 @@ -62,11 +97,9 @@ export const SetupStepsRoot: FC = props => { if (nextStepIndex < steps.length) { const nextStep = steps[nextStepIndex] - setStepId(nextStep.id) navigate(nextStep.path) - onStepChange(nextStep) } - }, [activeStepIndex, steps, navigate, onStepChange]) + }, [activeStepIndex, steps, navigate]) const handleGoToPrevStep = useCallback(() => { const prevStepIndex = activeStepIndex - 1 @@ -74,11 +107,9 @@ export const SetupStepsRoot: FC = props => { if (prevStepIndex >= 0) { const prevStep = steps[prevStepIndex] - setStepId(prevStep.id) navigate(prevStep.path) - onStepChange(prevStep) } - }, [activeStepIndex, steps, navigate, onStepChange]) + }, [activeStepIndex, steps, navigate]) const cachedContext = useMemo( () => ({ @@ -95,10 +126,10 @@ export const SetupStepsRoot: FC = props => {
- {availableSteps.map(step => ( + {steps.map(step => ( ))} - } /> + } />
Date: Tue, 7 Feb 2023 17:09:30 -0300 Subject: [PATCH 10/11] Fix URL match calculation logic --- .../src/setup-wizard/components/setup-steps/SetupSteps.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx index 507ec4b45054..3063e0202cd4 100644 --- a/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx +++ b/client/web/src/setup-wizard/components/setup-steps/SetupSteps.tsx @@ -79,11 +79,11 @@ export const SetupStepsRoot: FC = props => { } } - // Fallback on the last available step if URL doesn't match any step and we + // Fallback on the first available step if URL doesn't match any step, and we // don't have any pre-saved step return { - activeStepIndex: availableSteps.length - 1, - currentStep: availableSteps[availableSteps.length - 1], + activeStepIndex: 0, + currentStep: steps[0], } }, [location, initialStepId, steps]) From c0fe3806e869e1963a300d83d4e646590880bbcb Mon Sep 17 00:00:00 2001 From: Vova Kulikov Date: Wed, 8 Feb 2023 11:00:30 -0300 Subject: [PATCH 11/11] Revert setting cascade check --- client/web/src/SourcegraphWebApp.tsx | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/client/web/src/SourcegraphWebApp.tsx b/client/web/src/SourcegraphWebApp.tsx index a96e9373e3a4..56de0a2539f6 100644 --- a/client/web/src/SourcegraphWebApp.tsx +++ b/client/web/src/SourcegraphWebApp.tsx @@ -39,7 +39,7 @@ import { import { FilterType } from '@sourcegraph/shared/src/search/query/filters' import { filterExists } from '@sourcegraph/shared/src/search/query/validate' import { aggregateStreamingSearch } from '@sourcegraph/shared/src/search/stream' -import { SettingsCascadeOrError } from '@sourcegraph/shared/src/settings/settings' +import { EMPTY_SETTINGS_CASCADE, SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings' import { TemporarySettingsProvider } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsProvider' import { TemporarySettingsStorage } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsStorage' import { globbingEnabledFromSettings } from '@sourcegraph/shared/src/util/globbing' @@ -121,7 +121,7 @@ export interface SourcegraphWebAppProps routes: readonly LayoutRouteProps[] } -interface SourcegraphWebAppState { +interface SourcegraphWebAppState extends SettingsCascadeProps { error?: Error /** @@ -145,8 +145,6 @@ interface SourcegraphWebAppState { * Whether globbing is enabled for filters. */ globbing: boolean - - settingsCascade: SettingsCascadeOrError | null } const notificationStyles: BrandedNotificationItemStyleProps = { @@ -186,7 +184,7 @@ export class SourcegraphWebApp extends React.Component } - const { settingsCascade, authenticatedUser, graphqlClient, temporarySettingsStorage } = this.state + const { authenticatedUser, graphqlClient, temporarySettingsStorage } = this.state - if ( - authenticatedUser === undefined || - graphqlClient === undefined || - temporarySettingsStorage === undefined || - !settingsCascade - ) { + if (authenticatedUser === undefined || graphqlClient === undefined || temporarySettingsStorage === undefined) { return null } @@ -371,9 +364,11 @@ export class SourcegraphWebApp extends React.Component