Skip to content

Commit b2401d1

Browse files
authored
chore(web): text on welcome string reflects install target (#2369)
* chore(web): text on welcome string reflects install target * f * f
1 parent e801e7e commit b2401d1

File tree

11 files changed

+69
-82
lines changed

11 files changed

+69
-82
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ create-node%: DISTRO = debian-bookworm
343343
create-node%: NODE_PORT = 30000
344344
create-node%: MANAGER_NODE_PORT = 30080
345345
create-node%: K0S_DATA_DIR = /var/lib/embedded-cluster/k0s
346+
create-node%: ENABLE_V3 = 0
346347
create-node%:
347348
@docker run -d \
348349
--name node$* \
@@ -356,6 +357,7 @@ create-node%:
356357
$(if $(filter node0,node$*),-p $(MANAGER_NODE_PORT):$(MANAGER_NODE_PORT)) \
357358
$(if $(filter node0,node$*),-p 30003:30003) \
358359
-e EC_PUBLIC_ADDRESS=localhost \
360+
-e ENABLE_V3=$(ENABLE_V3) \
359361
replicated/ec-distro:$(DISTRO)
360362

361363
@$(MAKE) ssh-node$*

cmd/installer/cli/api.go

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414

1515
"github.com/gorilla/mux"
1616
"github.com/replicatedhq/embedded-cluster/api"
17-
apiclient "github.com/replicatedhq/embedded-cluster/api/client"
1817
apilogger "github.com/replicatedhq/embedded-cluster/api/pkg/logger"
1918
apitypes "github.com/replicatedhq/embedded-cluster/api/types"
2019
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
@@ -29,6 +28,7 @@ import (
2928

3029
// apiOptions holds the configuration options for the API server
3130
type apiOptions struct {
31+
InstallTarget string
3232
RuntimeConfig runtimeconfig.RuntimeConfig
3333
Logger logrus.FieldLogger
3434
MetricsReporter metrics.ReporterInterface
@@ -103,8 +103,9 @@ func serveAPI(ctx context.Context, listener net.Listener, cert tls.Certificate,
103103
}
104104

105105
webServer, err := web.New(web.InitialState{
106-
Title: opts.ReleaseData.Application.Spec.Title,
107-
Icon: opts.ReleaseData.Application.Spec.Icon,
106+
Title: opts.ReleaseData.Application.Spec.Title,
107+
Icon: opts.ReleaseData.Application.Spec.Icon,
108+
InstallTarget: opts.InstallTarget,
108109
}, web.WithLogger(logger), web.WithAssetsFS(opts.WebAssetsFS))
109110
if err != nil {
110111
return fmt.Errorf("new web server: %w", err)
@@ -123,7 +124,7 @@ func serveAPI(ctx context.Context, listener net.Listener, cert tls.Certificate,
123124
go func() {
124125
<-ctx.Done()
125126
logrus.Debugf("Shutting down API")
126-
server.Shutdown(context.Background())
127+
_ = server.Shutdown(context.Background())
127128
}()
128129

129130
return server.ServeTLS(listener, "", "")
@@ -177,45 +178,6 @@ func waitForAPI(ctx context.Context, addr string) error {
177178
}
178179
}
179180

180-
func markUIInstallComplete(password string, managerPort int, installErr error) error {
181-
httpClient := &http.Client{
182-
Transport: &http.Transport{
183-
Proxy: nil, // This is a local client so no proxy is needed
184-
TLSClientConfig: &tls.Config{
185-
InsecureSkipVerify: true,
186-
},
187-
},
188-
}
189-
apiClient := apiclient.New(
190-
fmt.Sprintf("https://localhost:%d", managerPort),
191-
apiclient.WithHTTPClient(httpClient),
192-
)
193-
if err := apiClient.Authenticate(password); err != nil {
194-
return fmt.Errorf("unable to authenticate: %w", err)
195-
}
196-
197-
var state apitypes.State
198-
var description string
199-
if installErr != nil {
200-
state = apitypes.StateFailed
201-
description = fmt.Sprintf("Installation failed: %v", installErr)
202-
} else {
203-
state = apitypes.StateSucceeded
204-
description = "Installation succeeded"
205-
}
206-
207-
_, err := apiClient.SetInstallStatus(apitypes.Status{
208-
State: state,
209-
Description: description,
210-
LastUpdated: time.Now(),
211-
})
212-
if err != nil {
213-
return fmt.Errorf("unable to set install status: %w", err)
214-
}
215-
216-
return nil
217-
}
218-
219181
func getManagerURL(hostname string, port int) string {
220182
if hostname != "" {
221183
return fmt.Sprintf("https://%s:%v", hostname, port)

cmd/installer/cli/install.go

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io/fs"
99
"os"
10+
"slices"
1011
"strings"
1112
"syscall"
1213
"time"
@@ -65,6 +66,7 @@ type InstallCmdFlags struct {
6566

6667
// guided UI flags
6768
enableManagerExperience bool
69+
target string
6870
managerPort int
6971
tlsCertFile string
7072
tlsKeyFile string
@@ -152,6 +154,13 @@ func InstallCmd(ctx context.Context, name string) *cobra.Command {
152154
}
153155

154156
func addInstallFlags(cmd *cobra.Command, flags *InstallCmdFlags) error {
157+
cmd.Flags().StringVar(&flags.target, "target", "linux", "The target platform to install to. Valid options are 'linux' or 'kubernetes'.")
158+
if os.Getenv("ENABLE_V3") != "1" {
159+
if err := cmd.Flags().MarkHidden("target"); err != nil {
160+
return err
161+
}
162+
}
163+
155164
cmd.Flags().StringVar(&flags.airgapBundle, "airgap-bundle", "", "Path to the air gap bundle. If set, the installation will complete without internet access.")
156165
cmd.Flags().StringVar(&flags.dataDir, "data-dir", ecv1beta1.DefaultDataDir, "Path to the data directory")
157166
cmd.Flags().IntVar(&flags.localArtifactMirrorPort, "local-artifact-mirror-port", ecv1beta1.DefaultLocalArtifactMirrorPort, "Port on which the Local Artifact Mirror will be served")
@@ -204,26 +213,33 @@ func addInstallAdminConsoleFlags(cmd *cobra.Command, flags *InstallCmdFlags) err
204213
}
205214

206215
func addManagerExperienceFlags(cmd *cobra.Command, flags *InstallCmdFlags) error {
207-
cmd.Flags().BoolVar(&flags.enableManagerExperience, "manager-experience", false, "Run the browser-based installation experience.")
216+
// If the ENABLE_V3 environment variable is set, default to the new manager experience and do
217+
// not hide the new flags.
218+
enableV3 := os.Getenv("ENABLE_V3") == "1"
219+
220+
cmd.Flags().BoolVar(&flags.enableManagerExperience, "manager-experience", enableV3, "Run the browser-based installation experience.")
221+
if err := cmd.Flags().MarkHidden("manager-experience"); err != nil {
222+
return err
223+
}
224+
208225
cmd.Flags().IntVar(&flags.managerPort, "manager-port", ecv1beta1.DefaultManagerPort, "Port on which the Manager will be served")
209226
cmd.Flags().StringVar(&flags.tlsCertFile, "tls-cert", "", "Path to the TLS certificate file")
210227
cmd.Flags().StringVar(&flags.tlsKeyFile, "tls-key", "", "Path to the TLS key file")
211228
cmd.Flags().StringVar(&flags.hostname, "hostname", "", "Hostname to use for TLS configuration")
212229

213-
if err := cmd.Flags().MarkHidden("manager-experience"); err != nil {
214-
return err
215-
}
216-
if err := cmd.Flags().MarkHidden("manager-port"); err != nil {
217-
return err
218-
}
219-
if err := cmd.Flags().MarkHidden("tls-cert"); err != nil {
220-
return err
221-
}
222-
if err := cmd.Flags().MarkHidden("tls-key"); err != nil {
223-
return err
224-
}
225-
if err := cmd.Flags().MarkHidden("hostname"); err != nil {
226-
return err
230+
if !enableV3 {
231+
if err := cmd.Flags().MarkHidden("manager-port"); err != nil {
232+
return err
233+
}
234+
if err := cmd.Flags().MarkHidden("tls-cert"); err != nil {
235+
return err
236+
}
237+
if err := cmd.Flags().MarkHidden("tls-key"); err != nil {
238+
return err
239+
}
240+
if err := cmd.Flags().MarkHidden("hostname"); err != nil {
241+
return err
242+
}
227243
}
228244

229245
return nil
@@ -238,6 +254,10 @@ func preRunInstall(cmd *cobra.Command, flags *InstallCmdFlags, rc runtimeconfig.
238254
// this does not return an error - it returns the previous umask
239255
_ = syscall.Umask(0o022)
240256

257+
if !slices.Contains([]string{"linux", "kubernetes"}, flags.target) {
258+
return fmt.Errorf(`invalid target (must be one of: "linux", "kubernetes")`)
259+
}
260+
241261
// license file can be empty for restore
242262
if flags.licenseFile != "" {
243263
b, err := os.ReadFile(flags.licenseFile)
@@ -414,10 +434,11 @@ func runManagerExperienceInstall(ctx context.Context, flags InstallCmdFlags, rc
414434
}
415435

416436
apiConfig := apiOptions{
437+
InstallTarget: flags.target,
438+
RuntimeConfig: rc,
417439
// TODO (@salah): implement reporting in api
418440
// MetricsReporter: installReporter,
419-
RuntimeConfig: rc,
420-
Password: flags.adminConsolePassword,
441+
Password: flags.adminConsolePassword,
421442
TLSConfig: apitypes.TLSConfig{
422443
CertBytes: flags.tlsCertBytes,
423444
KeyBytes: flags.tlsKeyBytes,

web/src/components/wizard/setup/LinuxSetup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface LinuxSetupProps {
3737
globalCidr?: string;
3838
};
3939
prototypeSettings: {
40-
clusterMode: string;
40+
installTarget: string;
4141
availableNetworkInterfaces?: Array<{
4242
name: string;
4343
}>;

web/src/components/wizard/tests/SetupStep.test.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const server = setupServer(
2626

2727
describe("SetupStep", () => {
2828
const mockOnNext = vi.fn();
29-
const mockOnBack = vi.fn();
3029

3130
beforeAll(() => {
3231
server.listen();
@@ -45,8 +44,8 @@ describe("SetupStep", () => {
4544
server.close();
4645
});
4746

48-
it("renders the linux setup form when it's embedded", async () => {
49-
renderWithProviders(<SetupStep onNext={mockOnNext} onBack={mockOnBack} />, {
47+
it("renders the linux setup form when the install target is linux", async () => {
48+
renderWithProviders(<SetupStep onNext={mockOnNext} />, {
5049
wrapperProps: {
5150
authenticated: true,
5251
preloadedState: {
@@ -127,7 +126,7 @@ describe("SetupStep", () => {
127126
})
128127
);
129128

130-
renderWithProviders(<SetupStep onNext={mockOnNext} onBack={mockOnBack} />, {
129+
renderWithProviders(<SetupStep onNext={mockOnNext} />, {
131130
wrapperProps: {
132131
authenticated: true,
133132
preloadedState: {
@@ -230,7 +229,7 @@ describe("SetupStep", () => {
230229
})
231230
);
232231

233-
renderWithProviders(<SetupStep onNext={mockOnNext} onBack={mockOnBack} />, {
232+
renderWithProviders(<SetupStep onNext={mockOnNext} />, {
234233
wrapperProps: {
235234
authenticated: true,
236235
preloadedState: {

web/src/contexts/ConfigContext.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ interface PrototypeSettings {
1818
failPreflights: boolean;
1919
failInstallation: boolean;
2020
failHostPreflights: boolean;
21-
clusterMode: 'existing' | 'embedded';
21+
installTarget: 'linux' | 'kubernetes';
2222
themeColor: string;
2323
skipNodeValidation: boolean;
2424
useSelfSignedCert: boolean;
@@ -47,7 +47,7 @@ const defaultPrototypeSettings: PrototypeSettings = {
4747
failPreflights: false,
4848
failInstallation: false,
4949
failHostPreflights: false,
50-
clusterMode: 'embedded',
50+
installTarget: 'linux',
5151
themeColor: '#316DE6',
5252
skipNodeValidation: false,
5353
useSelfSignedCert: false,

web/src/contexts/WizardModeContext.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { createContext, useContext } from "react";
2-
import { useConfig } from "./ConfigContext";
32
import { useBranding } from "./BrandingContext";
43

54
export type WizardMode = "install" | "upgrade";
@@ -19,13 +18,13 @@ interface WizardText {
1918
nextButtonText: string;
2019
}
2120

22-
const getTextVariations = (isEmbedded: boolean, title: string): Record<WizardMode, WizardText> => ({
21+
const getTextVariations = (isLinux: boolean, title: string): Record<WizardMode, WizardText> => ({
2322
install: {
2423
title: title || "",
2524
subtitle: "Installation Wizard",
2625
welcomeTitle: `Welcome to ${title}`,
2726
welcomeDescription: `This wizard will guide you through installing ${title} on your ${
28-
isEmbedded ? "Linux machine" : "Kubernetes cluster"
27+
isLinux ? "Linux machine" : "Kubernetes cluster"
2928
}.`,
3029
setupTitle: "Setup",
3130
setupDescription: "Configure the host settings for this installation.",
@@ -41,7 +40,7 @@ const getTextVariations = (isEmbedded: boolean, title: string): Record<WizardMod
4140
subtitle: "Upgrade Wizard",
4241
welcomeTitle: `Welcome to ${title}`,
4342
welcomeDescription: `This wizard will guide you through upgrading ${title} on your ${
44-
isEmbedded ? "Linux machine" : "Kubernetes cluster"
43+
isLinux ? "Linux machine" : "Kubernetes cluster"
4544
}.`,
4645
setupTitle: "Setup",
4746
setupDescription: "Set up the hosts to use for this upgrade.",
@@ -65,10 +64,12 @@ export const WizardModeProvider: React.FC<{
6564
children: React.ReactNode;
6665
mode: WizardMode;
6766
}> = ({ children, mode }) => {
68-
const { prototypeSettings } = useConfig();
67+
// __INITIAL_STATE__ is a global variable that can be set by the server-side rendering process
68+
// as a way to pass initial data to the client.
69+
const initialState = window.__INITIAL_STATE__ || {};
6970
const { title } = useBranding();
70-
const isEmbedded = prototypeSettings.clusterMode === "embedded";
71-
const text = getTextVariations(isEmbedded, title)[mode];
71+
const isLinux = initialState.installTarget === "linux";
72+
const text = getTextVariations(isLinux, title)[mode];
7273

7374
return <WizardModeContext.Provider value={{ mode, text }}>{children}</WizardModeContext.Provider>;
7475
};

web/src/global.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ declare global {
1010
interface InitialState {
1111
icon?: string;
1212
title?: string;
13+
installTarget?: string;
1314
}
1415
}

web/src/test/setup.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ interface PrototypeSettings {
2929
failPreflights: boolean;
3030
failInstallation: boolean;
3131
failHostPreflights: boolean;
32-
clusterMode: "existing" | "embedded";
32+
installTarget: "linux" | "kubernetes";
3333
themeColor: string;
3434
skipNodeValidation: boolean;
3535
useSelfSignedCert: boolean;
@@ -91,7 +91,7 @@ const MockProvider = ({ children, queryClient, contexts }: MockProviderProps) =>
9191

9292
return (
9393
<QueryClientProvider client={queryClient}>
94-
<AuthContext.Provider value={contexts.authContext}>
94+
<AuthContext.Provider value={{ ...contexts.authContext, isLoading: false }}>
9595
<ConfigContext.Provider value={contexts.configContext}>
9696
<BrandingContext.Provider value={contexts.brandingContext}>
9797
<WizardModeContext.Provider value={contexts.wizardModeContext}>{children}</WizardModeContext.Provider>
@@ -129,7 +129,7 @@ export const renderWithProviders = (
129129
failPreflights: false,
130130
failInstallation: false,
131131
failHostPreflights: false,
132-
clusterMode: "embedded",
132+
installTarget: "linux",
133133
themeColor: "#316DE6",
134134
skipNodeValidation: false,
135135
useSelfSignedCert: false,

web/src/test/testData.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export const MOCK_INSTALL_CONFIG = {
22
adminConsolePort: 8800,
33
localArtifactMirrorPort: 8801,
44
networkInterface: "eth0",
5-
clusterMode: "embedded",
5+
installTarget: "linux",
66
};
77

88
export const MOCK_NETWORK_INTERFACES = {
@@ -13,7 +13,7 @@ export const MOCK_NETWORK_INTERFACES = {
1313
};
1414

1515
export const MOCK_PROTOTYPE_SETTINGS = {
16-
clusterMode: "embedded",
16+
installTarget: "linux",
1717
title: "Test Cluster",
1818
description: "Test cluster configuration",
1919
};

0 commit comments

Comments
 (0)