This is an automated email from the ASF dual-hosted git repository.
arshad pushed a commit to branch frontend-refactor
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/frontend-refactor by this push:
new ea56ea09d3 AMBARI-26542: Ambari Web React: Kerberos Wizard context &
setup (#4052)
ea56ea09d3 is described below
commit ea56ea09d30ea3101d4a608c1d197754512a596f
Author: Sandeep Kumar <[email protected]>
AuthorDate: Tue Sep 9 11:06:45 2025 +0530
AMBARI-26542: Ambari Web React: Kerberos Wizard context & setup (#4052)
---
ambari-web/latest/src/api/kerberosApi.ts | 131 ++++++++++++
.../latest/src/components/ConfirmationModal.tsx | 4 +-
ambari-web/latest/src/constants.ts | 3 +-
.../KerberosWizard/KerberosStore/context.tsx | 235 +++++++++++++++++++++
.../KerberosWizard/KerberosStore/reducer.ts | 49 +++++
.../KerberosWizard/KerberosStore/types.ts} | 24 ++-
.../KerberosWizard/index.tsx} | 28 ++-
.../screens/KerberosWizard/kerberosWizardSteps.tsx | 121 +++++++++++
8 files changed, 571 insertions(+), 24 deletions(-)
diff --git a/ambari-web/latest/src/api/kerberosApi.ts
b/ambari-web/latest/src/api/kerberosApi.ts
new file mode 100644
index 0000000000..9107ed9cd9
--- /dev/null
+++ b/ambari-web/latest/src/api/kerberosApi.ts
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ambariApi } from "./config/axiosConfig";
+
+const KerberosApi = {
+ getKerberosDescriptorProperties: async function (
+ evaluate: string,
+ clusterName: string
+ ) {
+ const url =
`/clusters/${clusterName}/kerberos_descriptors/COMPOSITE?evaluate_when=${evaluate}&_=${Date.now()}`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "GET",
+ });
+ return response.data;
+ },
+
+ getSecurityType: async function (clusterName: string) {
+ const url = `clusters/${clusterName}?fields=Clusters/security_type`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "GET",
+ });
+ return response.data;
+ },
+
+ testKdcConnection: async function (kdcHosts: string) {
+ const url = `kdc_check/${kdcHosts}`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "GET",
+ });
+ return response.data;
+ },
+
+ downloadKerberosIdentitiesCsv: async function (clusterName: string) {
+ const url =
`clusters/${clusterName}/kerberos_identities?fields=*&format=csv`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "GET",
+ });
+ return response.data;
+ },
+ saveKerberosData: async function (clusterName: string, payload: any) {
+ const url = `clusters/${clusterName}/artifacts/kerberos_descriptor`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "POST",
+ data: payload,
+ });
+ return response.data;
+ },
+ postKDCAdminCredentials: async function (clusterName: string, payload: any) {
+ const url = `clusters/${clusterName}/credentials/kdc.admin.credential`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "POST",
+ data: payload,
+ });
+ return response.data;
+ },
+ deleteKDCAdminCredentials: async function (clusterName: string) {
+ const url = `clusters/${clusterName}/credentials/kdc.admin.credential`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "DELETE",
+ });
+ return response.data;
+ },
+ getKDCAdminCredentials: async function (clusterName: string) {
+ const url = `clusters/${clusterName}/credentials?fields=Credential/*`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "GET",
+ });
+ return response.data;
+ },
+
+ createKerberosConfigurations: async function (
+ clusterName: string,
+ payloadData: any
+ ) {
+ const url = `clusters/${clusterName}`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "PUT",
+ data: payloadData,
+ });
+ return response.data;
+ },
+
+ deleteKerberosService: async function (
+ clusterName: string,
+ serviceName: string
+ ) {
+ const url = `clusters/${clusterName}/services/${serviceName}`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "DELETE",
+ });
+ return response.data;
+ },
+
+ createAdminSession: async function (clusterName: string, payloadData: any) {
+ const url = `clusters/${clusterName}`;
+ const response = await ambariApi.request({
+ url: url,
+ method: "PUT",
+ data: payloadData,
+ });
+ return response.data;
+ },
+};
+
+export default KerberosApi;
diff --git a/ambari-web/latest/src/components/ConfirmationModal.tsx
b/ambari-web/latest/src/components/ConfirmationModal.tsx
index a776c0cea2..43c6fd95e9 100644
--- a/ambari-web/latest/src/components/ConfirmationModal.tsx
+++ b/ambari-web/latest/src/components/ConfirmationModal.tsx
@@ -21,8 +21,8 @@ import DefaultButton from "./DefaultButton";
type ConfirmationModalProps = {
isOpen: boolean;
onClose: () => void;
- modalTitle: string;
- modalBody: string;
+ modalTitle: any;
+ modalBody: any;
successCallback: () => void;
buttonVariant?: string;
cancellable?: boolean;
diff --git a/ambari-web/latest/src/constants.ts
b/ambari-web/latest/src/constants.ts
index 09d775ee8c..da554606cc 100644
--- a/ambari-web/latest/src/constants.ts
+++ b/ambari-web/latest/src/constants.ts
@@ -20,9 +20,10 @@ export enum ClusterProgressStatus {
ENABLING_NAMENODE_HA = "ENABLING_NAMENODE_HA",
ADDING_HOST = "ADDING_HOST",
ADDING_SERVICE = "ADDING_SERVICE",
+ ENABLING_KERBEROS = "ENABLING_KERBEROS",
}
export enum ProgressStatus {
IN_PROGRESS = "IN_PROGRESS",
COMPLETED = "COMPLETED",
FAILED = "FAILED",
-}
\ No newline at end of file
+}
diff --git
a/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/context.tsx
b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/context.tsx
new file mode 100644
index 0000000000..d860b1cec5
--- /dev/null
+++ b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/context.tsx
@@ -0,0 +1,235 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, {
+ createContext,
+ Dispatch,
+ // useContext,
+ useEffect,
+ useReducer,
+ useRef,
+ useState,
+} from "react";
+import { State, Action, ActionTypes } from "./types";
+import { reducer, initialState } from "./reducer";
+import ClusterApi from "../../../api/clusterApi";
+import { get, isEmpty } from "lodash";
+import { ClusterProgressStatus } from "../../../constants";
+// import ConfirmationModal from "../../../components/ConfirmationModal";
+// import { AppContext } from "../../../store/context";
+// import { translate } from "../../../Utils/Utility";
+import { useNavigate } from "react-router";
+import kerberosApi from "../../../api/kerberosApi";
+// import modalManager from "../../../store/ModalManager";
+import { RequestApi } from "../../../api/requestApi";
+
+interface KerberosWizardContextProps {
+ state: State;
+ dispatch: Dispatch<Action>;
+ stepWizardUtilities?: any;
+ flushStateToDb?: any;
+ onExitPopUp?: any;
+}
+
+export async function discardChanges(clusterName: string) {
+ const payload = {
+ Clusters: {
+ security_type: "NONE",
+ },
+ };
+ try {
+ await RequestApi.preparingOperations(clusterName, payload);
+ await kerberosApi.deleteKerberosService(clusterName, "KERBEROS");
+ } catch (error) {
+ console.log("Unable to remove kerberos", error);
+ }
+}
+
+export const EnableKerberosContext =
createContext<KerberosWizardContextProps>({
+ state: initialState,
+ dispatch: () => undefined,
+ flushStateToDb: () => undefined,
+ onExitPopUp: () => undefined,
+});
+
+export const KerberosWizardProvider: React.FC<{
+ stepWizardUtilities: any;
+ children: React.ReactNode;
+}> = ({ stepWizardUtilities, children }) => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ const isDataPersisted = useRef(false);
+ const [currStepData, setCurrStepData] = useState({});
+ // const { clusterName } = useContext(AppContext);
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ syncUserPersistedData();
+ }, []);
+
+ useEffect(() => {
+ if (isDataPersisted.current) {
+ flushCurrentData();
+ }
+ }, [state.kerberosWizardSteps, currStepData]);
+
+ async function syncUserPersistedData() {
+ try {
+ const persistedData = await ClusterApi.getPersistData(
+ "ENABLING_KERBEROS"
+ );
+ if (!isEmpty(get(persistedData, "kerberosWizardSteps", {}))) {
+ dispatch({
+ type: ActionTypes.SYNC_STATE,
+ payload: persistedData,
+ });
+ }
+ if (get(persistedData, "activeStep", "")) {
+ try {
+ const activeStepName = get(persistedData, "activeStep");
+ setCurrStepData({
+ progressStatus: ClusterProgressStatus.ENABLING_KERBEROS,
+ stepName: activeStepName,
+ });
+ let activeStepNumber = Object.keys(
+ stepWizardUtilities.wizardSteps
+ ).find((stepName) => {
+ return (
+ stepWizardUtilities.wizardSteps?.[stepName]?.name ===
+ activeStepName
+ );
+ });
+ stepWizardUtilities.jumpToStep(Number(activeStepNumber), true);
+ } catch (err) {
+ console.error("Error while jumping to step", err);
+ }
+ } else {
+ stepWizardUtilities.jumpToStep(1, true);
+ }
+ } finally {
+ isDataPersisted.current = true;
+ }
+ }
+
+ async function flushCurrentData() {
+ await ClusterApi.postPersistData(
+ JSON.stringify({
+ ENABLING_KERBEROS: JSON.stringify({
+ ...state,
+ activeStep: get(currStepData, "stepName", ""),
+ }),
+ CLUSTER_STATE: JSON.stringify(currStepData),
+ })
+ );
+ }
+
+ async function flushOnCancel() {
+ await ClusterApi.postPersistData(
+ JSON.stringify({
+ ENABLING_KERBEROS: JSON.stringify(initialState),
+ CLUSTER_STATE: JSON.stringify({}),
+ })
+ );
+ navigate(`/main/admin/kerberos/`);
+ }
+
+ async function flushOnStepChange(nextStep: number) {
+ if (nextStep >= 1) {
+ let nextStepDetails = stepWizardUtilities.wizardSteps?.[nextStep];
+ if (nextStepDetails?.keysToRemove) {
+ nextStepDetails.keysToRemove.forEach((key: string) => {
+ if (state?.kerberosWizardSteps?.[key]) {
+ dispatch({
+ type: ActionTypes.REMOVE_KEY,
+ payload: { key },
+ });
+ }
+ });
+ }
+ setCurrStepData({
+ progressStatus: ClusterProgressStatus.ENABLING_KERBEROS,
+ stepName: stepWizardUtilities?.wizardSteps?.[nextStep]?.name,
+ });
+ }
+ }
+
+ function flushStateToDb(
+ operation: string = "default",
+ jumpStep: number = -1
+ ) {
+ let activeStep = Object.keys(stepWizardUtilities.wizardSteps).find(
+ (stepName) => {
+ return (
+ stepWizardUtilities.wizardSteps?.[stepName]?.name ===
+ stepWizardUtilities.currentStep.name
+ );
+ }
+ );
+ switch (operation) {
+ case "cancel":
+ flushOnCancel();
+ break;
+ case "back":
+ flushOnStepChange(Number(activeStep) - 1);
+ break;
+ case "next":
+ flushOnStepChange(Number(activeStep) + 1);
+ break;
+ case "jump":
+ flushOnStepChange(jumpStep);
+ break;
+ default:
+ flushCurrentData();
+ }
+ }
+
+ function onExitPopUp(isCritical: boolean, skipDiscardChanges: boolean) {
+ console.log("Exit popup called", isCritical, skipDiscardChanges);
+ // TODO: will be added once modalManager PR is merged
+ // modalManager.show(
+ // <ConfirmationModal
+ // isOpen={true}
+ // onClose={() => modalManager.hide()}
+ // modalTitle={translate("popup.confirmation.commonHeader")}
+ // modalBody={
+ // isCritical
+ // ? translate("admin.kerberos.wizard.exit.critical.msg")
+ // : translate("admin.kerberos.wizard.exit.warning.msg")
+ // }
+ // successCallback={() => {
+ // if (!skipDiscardChanges) discardChanges(clusterName);
+ // flushStateToDb("cancel");
+ // modalManager.hide();
+ // }}
+ // />
+ // );
+ }
+
+ return (
+ <EnableKerberosContext.Provider
+ value={{
+ state,
+ dispatch,
+ stepWizardUtilities,
+ flushStateToDb,
+ onExitPopUp,
+ }}
+ >
+ {children}
+ </EnableKerberosContext.Provider>
+ );
+};
diff --git
a/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/reducer.ts
b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/reducer.ts
new file mode 100644
index 0000000000..82ba77c43a
--- /dev/null
+++ b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/reducer.ts
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { cloneDeep } from "lodash";
+import { State, Action, ActionTypes } from "./types";
+
+export const initialState: State = {
+ kerberosWizardSteps: {},
+};
+
+export const reducer = (state: State, action: Action): State => {
+ switch (action.type) {
+ case ActionTypes.STORE_INFORMATION:
+ const stateCopy = cloneDeep(state);
+ if (!stateCopy.kerberosWizardSteps) {
+ stateCopy.kerberosWizardSteps = {};
+ }
+ const enableHighAvailibilityRangerAdminSteps = cloneDeep(
+ stateCopy.kerberosWizardSteps
+ );
+ enableHighAvailibilityRangerAdminSteps[action.payload.step] =
+ action.payload;
+ stateCopy.kerberosWizardSteps = enableHighAvailibilityRangerAdminSteps;
+ return stateCopy;
+ case ActionTypes.SYNC_STATE:
+ return { ...action.payload };
+ case ActionTypes.REMOVE_KEY:
+ const updatedSteps = { ...state.kerberosWizardSteps };
+ delete updatedSteps[action.payload.key];
+ return { ...state, kerberosWizardSteps: updatedSteps };
+ default:
+ return state;
+ }
+};
diff --git a/ambari-web/latest/src/constants.ts
b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/types.ts
similarity index 68%
copy from ambari-web/latest/src/constants.ts
copy to ambari-web/latest/src/screens/KerberosWizard/KerberosStore/types.ts
index 09d775ee8c..a492493bf5 100644
--- a/ambari-web/latest/src/constants.ts
+++ b/ambari-web/latest/src/screens/KerberosWizard/KerberosStore/types.ts
@@ -15,14 +15,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-export enum ClusterProgressStatus {
- PROVISIONING = "PROVISIONING",
- ENABLING_NAMENODE_HA = "ENABLING_NAMENODE_HA",
- ADDING_HOST = "ADDING_HOST",
- ADDING_SERVICE = "ADDING_SERVICE",
+
+export interface State {
+ kerberosWizardSteps: any;
}
-export enum ProgressStatus {
- IN_PROGRESS = "IN_PROGRESS",
- COMPLETED = "COMPLETED",
- FAILED = "FAILED",
-}
\ No newline at end of file
+
+export enum ActionTypes {
+ STORE_INFORMATION = "STORE INFORMATION",
+ SYNC_STATE = "SYNC STATE",
+ REMOVE_KEY = "REMOVE KEY",
+}
+
+export type Action =
+ | { type: ActionTypes.STORE_INFORMATION; payload: any }
+ | { type: ActionTypes.SYNC_STATE; payload: any }
+ | { type: ActionTypes.REMOVE_KEY; payload: any };
diff --git a/ambari-web/latest/src/constants.ts
b/ambari-web/latest/src/screens/KerberosWizard/index.tsx
similarity index 58%
copy from ambari-web/latest/src/constants.ts
copy to ambari-web/latest/src/screens/KerberosWizard/index.tsx
index 09d775ee8c..13cdd3e1a7 100644
--- a/ambari-web/latest/src/constants.ts
+++ b/ambari-web/latest/src/screens/KerberosWizard/index.tsx
@@ -15,14 +15,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-export enum ClusterProgressStatus {
- PROVISIONING = "PROVISIONING",
- ENABLING_NAMENODE_HA = "ENABLING_NAMENODE_HA",
- ADDING_HOST = "ADDING_HOST",
- ADDING_SERVICE = "ADDING_SERVICE",
-}
-export enum ProgressStatus {
- IN_PROGRESS = "IN_PROGRESS",
- COMPLETED = "COMPLETED",
- FAILED = "FAILED",
-}
\ No newline at end of file
+
+import StepWizard from "../../components/StepWizard";
+import useStepWizard from "../../hooks/useStepWizard";
+import { KerberosWizardProvider } from "./KerberosStore/context";
+import kerberosWizardSteps from "./kerberosWizardSteps";
+
+const KerberosWizard: React.FC = () => {
+ const stepWizardUtilities = useStepWizard(kerberosWizardSteps, 1, () => {});
+
+ return (
+ <KerberosWizardProvider stepWizardUtilities={stepWizardUtilities}>
+ <StepWizard wizardUtilities={stepWizardUtilities} />
+ </KerberosWizardProvider>
+ );
+};
+
+export default KerberosWizard;
diff --git
a/ambari-web/latest/src/screens/KerberosWizard/kerberosWizardSteps.tsx
b/ambari-web/latest/src/screens/KerberosWizard/kerberosWizardSteps.tsx
new file mode 100644
index 0000000000..7b91ce869e
--- /dev/null
+++ b/ambari-web/latest/src/screens/KerberosWizard/kerberosWizardSteps.tsx
@@ -0,0 +1,121 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default {
+ 1: {
+ label: "Get Started",
+ completed: false,
+ Component: <h1>Get Started</h1>,
+ canGoBack: false,
+ isNextEnabled: false,
+ name: "GET_STARTED",
+ keysToRemove: [
+ "CONFIGURE_KERBEROS",
+ "CONFIGURE_IDENTITIES",
+ "INSTALL_AND_TEST_KERBEROS_CLIENT",
+ "CONFIRM_CONFIGURATION",
+ "STOP_SERVICES",
+ "KERBERIZE_CLUSTER",
+ "START_AND_TEST_SERVICES",
+ ],
+ },
+ 2: {
+ label: "Configure Kerberos",
+ completed: false,
+ Component: <h1>Configure Kerberos</h1>,
+ canGoBack: true,
+ isNextEnabled: false,
+ name: "CONFIGURE_KERBEROS",
+ keysToRemove: [
+ "CONFIGURE_IDENTITIES",
+ "INSTALL_AND_TEST_KERBEROS_CLIENT",
+ "CONFIRM_CONFIGURATION",
+ "STOP_SERVICES",
+ "KERBERIZE_CLUSTER",
+ "START_AND_TEST_SERVICES",
+ ],
+ },
+ 3: {
+ label: "Install and Test Kerberos Client",
+ completed: false,
+ Component: <h1>Install and Test kerberos client</h1>,
+ canGoBack: true,
+ isNextEnabled: false,
+ name: "INSTALL_AND_TEST_KERBEROS_CLIENT",
+ keysToRemove: [
+ "CONFIGURE_IDENTITIES",
+ "CONFIRM_CONFIGURATION",
+ "STOP_SERVICES",
+ "KERBERIZE_CLUSTER",
+ "START_AND_TEST_SERVICES",
+ ],
+ },
+ 4: {
+ label: "Configure Identities",
+ completed: false,
+ Component: <h1>Configure Identities</h1>,
+ canGoBack: true,
+ isNextEnabled: true,
+ name: "CONFIGURE_IDENTITIES",
+ keysToRemove: [
+ "CONFIRM_CONFIGURATION",
+ "STOP_SERVICES",
+ "KERBERIZE_CLUSTER",
+ "START_AND_TEST_SERVICES",
+ ],
+ },
+ 5: {
+ label: "Confirm Configuration",
+ completed: false,
+ Component: <h1>Confirm Configuration</h1>,
+ canGoBack: true,
+ isNextEnabled: true,
+ name: "CONFIRM_CONFIGURATION",
+ keysToRemove: [
+ "STOP_SERVICES",
+ "KERBERIZE_CLUSTER",
+ "START_AND_TEST_SERVICES",
+ ],
+ },
+ 6: {
+ label: "Stop Services",
+ completed: false,
+ Component: <h1>Stop services</h1>,
+ canGoBack: true,
+ isNextEnabled: true,
+ name: "STOP_SERVICES",
+ keysToRemove: ["KERBERIZE_CLUSTER", "START_AND_TEST_SERVICES"],
+ },
+ 7: {
+ label: "Kerberize cluster",
+ completed: false,
+ Component: <h1>Kerberize cluster</h1>,
+ canGoBack: true,
+ isNextEnabled: false,
+ name: "KERBERIZE_CLUSTER",
+ keysToRemove: ["START_AND_TEST_SERVICES"],
+ },
+ 8: {
+ label: "Start and Test Services",
+ completed: false,
+ Component: <h1>Start and Test Services</h1>,
+ canGoBack: true,
+ isNextEnabled: false,
+ name: "START_AND_TEST_SERVICES",
+ },
+};
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]