|
|
@@ -1,13 +1,36 @@
|
|
|
-import { proxy } from "valtio";
|
|
|
+import { useEffect } from "react";
|
|
|
+import { useLocation } from "react-router";
|
|
|
+import { useRouting } from "shared/routing";
|
|
|
+import { proxy, useSnapshot } from "valtio";
|
|
|
+import { devtools } from "valtio/utils";
|
|
|
import { StepKey, Steps } from "../types";
|
|
|
import { StateKeys } from "./StateHandler";
|
|
|
|
|
|
type Step = {
|
|
|
previous?: StepKey;
|
|
|
url: string;
|
|
|
- next?: StepKey;
|
|
|
final?: true;
|
|
|
- state_key: StateKeys;
|
|
|
+ substeps?: {
|
|
|
+ [key in string]: SubStep;
|
|
|
+ };
|
|
|
+ on?: ActionHandler;
|
|
|
+ execute?: {
|
|
|
+ on: {
|
|
|
+ skip?: string;
|
|
|
+ continue?: string;
|
|
|
+ };
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+type SubStep = Omit<Step, "previous"> & {
|
|
|
+ parent: StepKey;
|
|
|
+ previous?: string;
|
|
|
+};
|
|
|
+
|
|
|
+export type Action = "skip" | "continue";
|
|
|
+type ActionHandler = {
|
|
|
+ skip?: string;
|
|
|
+ continue: string;
|
|
|
};
|
|
|
|
|
|
export type FlowType = {
|
|
|
@@ -22,39 +45,138 @@ const flow: FlowType = {
|
|
|
steps: {
|
|
|
new_project: {
|
|
|
url: "/onboarding/new-project",
|
|
|
- next: "connect_source",
|
|
|
- state_key: "project",
|
|
|
+ on: {
|
|
|
+ continue: "connect_source",
|
|
|
+ },
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveProjectData",
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
connect_source: {
|
|
|
previous: "new_project",
|
|
|
url: "/onboarding/source",
|
|
|
- next: "connect_registry",
|
|
|
- state_key: "connected_source",
|
|
|
+ on: {
|
|
|
+ continue: "connect_registry",
|
|
|
+ },
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveSelectedSource",
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
connect_registry: {
|
|
|
previous: "connect_source",
|
|
|
url: "/onboarding/registry",
|
|
|
- next: "provision_resources",
|
|
|
- state_key: "connected_registry",
|
|
|
+ on: {
|
|
|
+ skip: "provision_resources",
|
|
|
+ continue: "connect_registry.credentials",
|
|
|
+ },
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ skip: "skipRegistryConnection",
|
|
|
+ continue: "saveRegistryProvider",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ substeps: {
|
|
|
+ credentials: {
|
|
|
+ url: "/onboarding/registry/credentials",
|
|
|
+ on: {
|
|
|
+ continue: "connect_registry.settings",
|
|
|
+ },
|
|
|
+ parent: "connect_registry",
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveRegistryCredentials",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ settings: {
|
|
|
+ previous: "credentials",
|
|
|
+ url: "/onboarding/registry/settings",
|
|
|
+ on: {
|
|
|
+ continue: "connect_registry.test_connection",
|
|
|
+ },
|
|
|
+ parent: "connect_registry",
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveRegistrySettings",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ test_connection: {
|
|
|
+ previous: "settings",
|
|
|
+ url: "/onboarding/registry/test_connection",
|
|
|
+ on: {
|
|
|
+ continue: "provision_resources",
|
|
|
+ },
|
|
|
+ parent: "connect_registry",
|
|
|
+ },
|
|
|
+ },
|
|
|
},
|
|
|
provision_resources: {
|
|
|
- final: true,
|
|
|
previous: "connect_registry",
|
|
|
url: "/onboarding/provision",
|
|
|
- state_key: "provision_resources",
|
|
|
+ on: {
|
|
|
+ skip: "provision_resources.connect_own_cluster",
|
|
|
+ continue: "provision_resources.credentials",
|
|
|
+ },
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ skip: "skipResourceProvisioning",
|
|
|
+ continue: "saveResourceProvisioningProvider",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ substeps: {
|
|
|
+ connect_own_cluster: {
|
|
|
+ url: "/onboarding/provision/connect_own_cluster",
|
|
|
+ on: {
|
|
|
+ continue: "clean_up",
|
|
|
+ },
|
|
|
+ parent: "provision_resources",
|
|
|
+ },
|
|
|
+ credentials: {
|
|
|
+ url: "/onboarding/provision/credentials",
|
|
|
+ on: { continue: "settings" },
|
|
|
+ parent: "provision_resources",
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveResourceProvisioningCredentials",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ settings: {
|
|
|
+ previous: "credentials",
|
|
|
+ url: "/onboarding/provision/settings",
|
|
|
+ on: {
|
|
|
+ continue: "clean_up",
|
|
|
+ },
|
|
|
+ parent: "provision_resources",
|
|
|
+ execute: {
|
|
|
+ on: {
|
|
|
+ continue: "saveResourceProvisioningSettings",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ clean_up: {
|
|
|
+ final: true,
|
|
|
+ url: "/dashboard?tab=provisioner",
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
|
|
|
type StepHandlerType = {
|
|
|
flow: FlowType;
|
|
|
- currentStepName: StepKey;
|
|
|
- currentStep: Step;
|
|
|
- finishedOnboarding: boolean;
|
|
|
+ currentStepName: string;
|
|
|
+ currentStep: Step | SubStep;
|
|
|
actions: {
|
|
|
- nextStep: () => void;
|
|
|
+ nextStep: (action?: Action) => void;
|
|
|
clearState: () => void;
|
|
|
restoreState: (prevState: StepHandlerType) => void;
|
|
|
+ getStep: (nextStepName: string) => Step | SubStep;
|
|
|
};
|
|
|
};
|
|
|
|
|
|
@@ -62,28 +184,59 @@ export const StepHandler: StepHandlerType = proxy({
|
|
|
flow,
|
|
|
currentStepName: flow.initial,
|
|
|
currentStep: flow.steps[flow.initial],
|
|
|
- finishedOnboarding: false,
|
|
|
actions: {
|
|
|
- nextStep: () => {
|
|
|
+ nextStep: (action: Action = "continue") => {
|
|
|
const cs = StepHandler.currentStep;
|
|
|
+
|
|
|
if (cs.final) {
|
|
|
- StepHandler.finishedOnboarding = true;
|
|
|
return;
|
|
|
}
|
|
|
- const nextStepName = cs.next;
|
|
|
- const nextStep = flow.steps[nextStepName];
|
|
|
- StepHandler.currentStep = nextStep;
|
|
|
+
|
|
|
+ const nextStepName = cs.on[action];
|
|
|
+
|
|
|
+ if (!nextStepName) {
|
|
|
+ throw new Error(
|
|
|
+ "No next step name found, fix the action triggering nextStep"
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
StepHandler.currentStepName = nextStepName;
|
|
|
+ StepHandler.currentStep = StepHandler.actions.getStep(nextStepName);
|
|
|
return;
|
|
|
},
|
|
|
+ getStep: (nextStepName: string) => {
|
|
|
+ const [stepName, substep] = nextStepName.split(".");
|
|
|
+
|
|
|
+ const step = flow.steps[stepName as Steps];
|
|
|
+
|
|
|
+ let nextStep: Step | SubStep = step;
|
|
|
+
|
|
|
+ if (substep) {
|
|
|
+ nextStep = step.substeps[substep];
|
|
|
+ }
|
|
|
+ return nextStep;
|
|
|
+ },
|
|
|
clearState: () => {
|
|
|
StepHandler.currentStepName = flow.initial;
|
|
|
StepHandler.currentStep = flow.steps[flow.initial];
|
|
|
- StepHandler.finishedOnboarding = false;
|
|
|
},
|
|
|
restoreState: (prevState) => {
|
|
|
StepHandler.currentStepName = prevState.currentStepName;
|
|
|
- StepHandler.currentStep = prevState.currentStep;
|
|
|
+ StepHandler.currentStep = StepHandler.actions.getStep(
|
|
|
+ prevState.currentStepName
|
|
|
+ );
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
+
|
|
|
+export const useSteps = () => {
|
|
|
+ const snap = useSnapshot(StepHandler);
|
|
|
+ const location = useLocation();
|
|
|
+ const { pushFiltered } = useRouting();
|
|
|
+ useEffect(() => {
|
|
|
+ if (snap.currentStepName === "clean_up") {
|
|
|
+ StepHandler.actions.clearState();
|
|
|
+ }
|
|
|
+ pushFiltered(snap.currentStep.url, ["tab"]);
|
|
|
+ }, [location.pathname, snap.currentStep?.url]);
|
|
|
+};
|